/* passport-object.css: the Passport booklet, the one signature object on the
   public pages. Spec: docs/superpowers/specs/2026-10-01-public-pages-passport-design.md
   CSS only. Motion keys off .page-snap-enter (added by the landing's snap
   observer) and plays once; nothing loops. Every colour is a token on .ppo:
   cobalt is the only accent, red exists only for the 404 stamp. No text under
   12px. Pages set --ppo-w / --ppo-h from their own stylesheet. */

.ppo {
  --ppo-cobalt: #1f49ff;
  --ppo-cobalt-deep: #1532b5;
  --ppo-cobalt-light: #4b6cff;
  --ppo-ink: #101012;
  --ppo-ink-2: #3d3d42;
  --ppo-ink-3: #6e6e75;
  --ppo-paper: #fcfcfd;
  --ppo-rule: #e6e6ea;
  --ppo-red: #c62828;
  --ppo-mono: 'JetBrains Mono', ui-monospace, monospace;
  --ppo-display: 'Inter', system-ui, sans-serif;
  --ppo-ease: cubic-bezier(.2, .7, .2, 1);
  /* A page's own edge: a 1px line so it holds on white, a tight contact
     shadow, then the product shadow. */
  --ppo-edge: 0 0 0 1px rgba(16, 16, 18, .08), 0 2px 3px -1px rgba(16, 16, 18, .12), 0 14px 30px -12px rgba(16, 16, 18, .22);
  --ppo-w: 280px;
  --ppo-h: 392px;
  position: relative;
  perspective: 2200px;
}

/* At rest the booklet lies flat (no transform), so its text is never
   resampled. 3D lives only inside the motion: the cover flip and the page turn,
   both of which end at rotateY(0). preserve-3d lets .ppo's perspective reach them. */
.ppo-spread {
  position: relative;
  display: flex;
  transform: none;
  transform-style: preserve-3d;
}

.ppo-page {
  position: relative;
  width: var(--ppo-w);
  min-height: var(--ppo-h);
  padding: 24px 22px 48px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  color: var(--ppo-ink);
  background-color: var(--ppo-paper);
  background-image: repeating-radial-gradient(circle at 50% 46%, rgba(31, 73, 255, .035) 0 1px, transparent 1px 7px);
  box-shadow: var(--ppo-edge);
}
.ppo-page.is-left {
  border-radius: 14px 3px 3px 14px;
  box-shadow: inset -22px 0 26px -20px rgba(16, 16, 18, .22), var(--ppo-edge);
}
.ppo-page.is-right {
  border-radius: 3px 14px 14px 3px;
  box-shadow: inset 22px 0 26px -20px rgba(16, 16, 18, .22), var(--ppo-edge);
  transform-origin: left center;
}
.ppo-page.is-solo { border-radius: 14px; }
.ppo-page:has(.ppo-mrz) { padding-bottom: 76px; }

.ppo-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--ppo-rule);
  font: 600 12px/1 var(--ppo-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ppo-ink-3);
}
.ppo-head b { color: var(--ppo-cobalt); font-weight: 600; }

/* Identity page */
.ppo-id { display: grid; grid-template-columns: 74px minmax(0, 1fr); gap: 16px; align-items: start; }
.ppo-photo {
  height: 90px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  font: 600 26px/1 var(--ppo-display);
  letter-spacing: -.02em;
  color: var(--ppo-cobalt);
  background-color: #eef1ff;
  background-image: repeating-radial-gradient(circle at 50% 120%, rgba(31, 73, 255, .08) 0 1px, transparent 1px 5px);
}
.ppo-fields { display: grid; gap: 10px; margin: 0; }
.ppo-fields dt {
  font: 600 12px/1.2 var(--ppo-mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ppo-ink-3);
}
.ppo-fields dd { margin: 2px 0 0; font-size: 15px; font-weight: 600; letter-spacing: -.01em; color: var(--ppo-ink); }
/* A blank passport (landing 07), read as a document not yet issued, not a form
   to fill in: the photo is a dashed outline on the paper (the same line as an
   empty entries box), in the mono labels' grey so it holds 5:1, with the crest
   faint inside it, awaiting issue; an empty field prints a short nil dash, as
   a data page or a table does, instead of an input's underline. */
.ppo-photo.is-blank { background-color: transparent; background-image: none; border: 1.5px dashed var(--ppo-ink-3); border-radius: 7px; }
.ppo-photo.is-blank::before { content: 'P'; content: 'P' / ''; display: grid; place-items: center; width: 40px; height: 40px; border: 1.5px solid currentColor; border-radius: 50%; font: 600 20px/1 var(--ppo-display); color: var(--ppo-cobalt); opacity: .16; }
.ppo-fields dd:empty { height: 18px; background: linear-gradient(var(--ppo-ink-3), var(--ppo-ink-3)) left center / 12px 1.5px no-repeat; }
/* Who can read: per-app switches, a visa-style table above the MRZ. It sits
   at the foot of the page and clears the two MRZ lines (they reach 81px up). */
.ppo-access { display: grid; margin: auto 0 18px; }
.ppo-access-title {
  padding-bottom: 8px;
  border-bottom: 1px solid var(--ppo-rule);
  font: 600 12px/1.2 var(--ppo-mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ppo-ink-3);
}
.ppo-access-app {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 9px 0;
  border-bottom: 1px solid var(--ppo-rule);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ppo-ink);
}
.ppo-mrz {
  position: absolute;
  left: 22px;
  right: 22px;
  bottom: 44px;
  margin: 0;
  font: 500 12px/1.55 var(--ppo-mono);
  letter-spacing: .08em;
  color: var(--ppo-ink-3);
  white-space: nowrap;
  overflow: hidden;
}
.ppo-example {
  position: absolute;
  right: 16px;
  bottom: 14px;
  padding: 4px 8px;
  border: 1px solid var(--ppo-rule);
  border-radius: 999px;
  background: var(--ppo-paper);
  font: 600 12px/1 var(--ppo-mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ppo-ink-3);
}

/* Stamps: ink inside the booklet, never badges on the page (#118). */
.ppo-stamp {
  --r: -4deg;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 9px 12px 8px;
  border: 2px solid currentColor;
  border-radius: 7px;
  box-shadow: inset 0 0 0 2px var(--ppo-paper), inset 0 0 0 3px currentColor;
  font: 600 14px/1 var(--ppo-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ppo-cobalt);
  mix-blend-mode: multiply;
  transform: rotate(var(--r));
  white-space: nowrap;
}
.ppo-stamp small { font: 600 12px/1 var(--ppo-mono); letter-spacing: .1em; }
.ppo-stamp.is-round { width: 96px; height: 96px; padding: 0; border-radius: 50%; justify-content: center; font-size: 13px; }
.ppo-stamp.is-request,
.ppo-stamp.is-ghost {
  color: var(--ppo-ink-3);
  border-width: 1.5px;
  border-style: dashed;
  box-shadow: none;
  mix-blend-mode: normal;
}
.ppo-stamp.is-ghost { border-color: var(--ppo-rule); }
.ppo-stamp.is-red { color: var(--ppo-red); }

/* Cover: flips open once on load, then is gone: its back face is hidden, and
   it ends visibility: hidden for browsers without backface-visibility (Safari
   before 15.4). It never takes a click, even mid-flip. It RESTS open: its own
   style is the flip's end state, so wherever the animation doesn't run
   (screenshots with animations off, reader modes, print) the spread shows
   open. The flip starts from the closed frame, which the backwards fill holds
   through the 0.5s delay, and lets go at the end. */
.ppo-cover {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 50%;
  border-radius: 3px 14px 14px 3px;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 24px;
  color: #fff;
  background-color: var(--ppo-cobalt);
  background-image:
    radial-gradient(circle at 50% 50%, transparent 0 58px, rgba(255, 255, 255, .06) 58px 59px, transparent 59px 66px, rgba(255, 255, 255, .05) 66px 67px, transparent 67px),
    linear-gradient(155deg, var(--ppo-cobalt-light) 0%, var(--ppo-cobalt) 42%, var(--ppo-cobalt-deep) 100%);
  box-shadow: inset 10px 0 18px -10px rgba(0, 0, 0, .35);
  transform-origin: left center;
  transform: rotateY(-180deg);
  visibility: hidden;
  backface-visibility: hidden;
  pointer-events: none;
  animation: ppo-open .9s var(--ppo-ease) .5s backwards;
}
.ppo-cover-title { font: 600 14px/1 var(--ppo-mono); letter-spacing: .5em; padding-left: .5em; text-transform: uppercase; }
.ppo-crest {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .6);
  display: grid;
  place-items: center;
  font: 600 44px/1 var(--ppo-display);
}

/* Closed (landing 06): the cover alone, lying flat, one page wide in a
   passport's own proportions. It never moves, so it is not the flipping
   .ppo-cover (which phones and reduced motion hide) but a class of its own.
   It reads as the same booklet shut: square at the spine, the open pages'
   edge and shadow, the page block showing 4px at the fore-edge (paper and
   rule, page by page), and the crest pressed into the board. */
.ppo-closed {
  position: relative;
  width: var(--ppo-w);
  aspect-ratio: 88 / 125;
  border-radius: 2px 14px 14px 2px;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 24px;
  color: #fff;
  background-color: var(--ppo-cobalt);
  background-image:
    radial-gradient(circle at 50% 50%, transparent 0 58px, rgba(255, 255, 255, .06) 58px 59px, transparent 59px 66px, rgba(255, 255, 255, .05) 66px 67px, transparent 67px),
    linear-gradient(155deg, var(--ppo-cobalt-light) 0%, var(--ppo-cobalt) 42%, var(--ppo-cobalt-deep) 100%);
  box-shadow: inset 10px 0 18px -10px rgba(0, 0, 0, .35), var(--ppo-edge);
}
.ppo-closed::after { content: ''; position: absolute; top: 10px; bottom: 10px; right: -4px; width: 4px; border-radius: 0 3px 3px 0; background: repeating-linear-gradient(90deg, var(--ppo-paper) 0 1px, var(--ppo-rule) 1px 2px); box-shadow: 1px 0 0 rgba(16, 16, 18, .12); }
.ppo-closed .ppo-crest { color: rgba(255, 255, 255, .88); border-color: rgba(255, 255, 255, .42); box-shadow: inset 0 2px 3px rgba(0, 0, 0, .3), 0 1px 0 rgba(255, 255, 255, .16); text-shadow: 0 -1px 0 rgba(0, 0, 0, .3), 0 1px 0 rgba(255, 255, 255, .16); }

@keyframes ppo-open { from { transform: rotateY(0deg); visibility: visible; } to { transform: rotateY(-180deg); visibility: hidden; } }
@keyframes ppo-turn { from { transform: rotateY(-32deg); opacity: .35; } to { transform: rotateY(0deg); opacity: 1; } }
@keyframes ppo-press {
  0% { opacity: 0; transform: rotate(var(--r)) scale(1.35); }
  70% { opacity: 1; transform: rotate(var(--r)) scale(.97); }
  100% { opacity: 1; transform: rotate(var(--r)) scale(1); }
}
/* backwards, not both: once turned or pressed the animation lets go, so the
   resting page or stamp is painted like any other ink (a held animation keeps
   it on its own layer, a shade softer than the page). The stamp also hides
   through its delay. */
.page-snap-enter .ppo-page.is-right { animation: ppo-turn .6s var(--ppo-ease) backwards; }
.page-snap-enter .ppo-stamp { animation: ppo-press .18s var(--ppo-ease) backwards; animation-delay: calc(.3s + var(--i, 0) * 90ms); }

/* Phones: one booklet opened top to bottom. The pages stack flat with no gap,
   outer corners round, and the join is a fold: a 1px rule with the gutter's
   shading on both sides. No cover, no page turn; nothing overlays text. */
@media (max-width: 768.98px) {
  .ppo { --ppo-w: 100%; --ppo-h: 0px; perspective: none; }
  .ppo-spread { flex-direction: column; gap: 0; transform: none; }
  .ppo-page.is-left { border-radius: 14px 14px 3px 3px; box-shadow: inset 0 -22px 26px -20px rgba(16, 16, 18, .22), var(--ppo-edge); }
  .ppo-page.is-right { border-radius: 3px 3px 14px 14px; box-shadow: inset 0 1px 0 var(--ppo-rule), inset 0 22px 26px -20px rgba(16, 16, 18, .22), var(--ppo-edge); }
  .ppo-cover { display: none; }
  .page-snap-enter .ppo-page.is-right { animation: none; }
}

/* Nothing in the booklet moves. passport-common.css only clamps motion to
   0.01ms, which still starts it (and, with transition-property's default of
   all, turns every style change into a transition). */
@media (prefers-reduced-motion: reduce) {
  .ppo-spread { transform: none; }
  .ppo-cover { display: none; }
  .ppo, .ppo *, .ppo *::before, .ppo *::after { animation: none !important; transition: none !important; }
}
