/* ==========================================================================
   PEPLII LANDING — page composition.
   Every token and primitive lives in console.css. This file only arranges.

   THE ARCHITECTURE: nine folds, one idea each, long scroll. Room art from the
   app goes FULL-BLEED as a fold's media layer with a scrim over it and the
   content on top. Folds alternate between scene (dark, cinematic, ink island)
   and paper (flat, quiet, where people actually read). Gradient seams top and
   bottom of every scene so the rooms bleed into one another instead of
   butting up against hard edges.

   MOTION BUDGET: three earned moments, not fade-on-scroll everywhere.
     1. the hero entrance sequence
     2. the statement lighting word by word
     3. the scrubbed day in fold 03
   Plus sibling stagger on two real lists. That's the whole budget.

   THE VISIBLE-BY-DEFAULT RULE: nothing on this page is hidden waiting for a
   class. CSS ships the finished state; `html.js` opts into the "start hidden"
   variants. A headless renderer, a background tab, or a JS failure all get a
   complete, readable page.
   ========================================================================== */

:root {
  /* 4pt scale */
  --s-1:  4px;
  --s-2:  8px;
  --s-3:  12px;
  --s-4:  16px;
  --s-5:  24px;
  --s-6:  32px;
  --s-7:  48px;
  --s-8:  64px;
  --s-9:  96px;

  /* fold rhythm: generous, and it breathes on bigger screens */
  --fold-y: clamp(72px, 11vw, 148px);

  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);

  --z-scene:   0;
  --z-scrim:   1;
  --z-content: 2;
  --z-topbar:  40;
  --z-skip:    100;
}

/* ------------------------------------------------------------------ base -- */

/* The topbar is fixed, so every in-page anchor (the whole footer nav) would
   otherwise land with its heading tucked underneath it. */
html { scroll-padding-top: 84px; }

/* Pixelify Sans ships a broken lowercase "fi" ligature: it renders as a capital
   A. "start to finish" came out "start to Anish", and "selfie" was next. Killed
   at the body so it can't come back the moment someone writes new display copy
   in a selector this rule didn't anticipate. The reading face loses fi/fl too,
   which is imperceptible at these sizes and worth the immunity. */
body {
  overflow-x: hidden;
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "clig" 0;
}

.px { image-rendering: pixelated; }

/* The clamp minimum is the TOTAL gutter, so 2.5rem is 20px a side on a phone.
   2rem left 16px, which reads as text hanging off the edge on a small screen. */
.wrap   { width: min(1160px, 100% - clamp(2.5rem, 8vw, 5rem)); margin-inline: auto; }
.narrow { width: min(760px,  100% - clamp(2.5rem, 8vw, 5rem)); margin-inline: auto; }

/* Pixelify renders 2 as 8 and 5 as S at display sizes. Anything a reader must
   read exactly moves to the reading face. Same rule the app applies with sf(). */
.figure b, .day b, .hud-chip b, .plan__price b, .steps__n {
  font-family: var(--sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}

.btn--lg { min-height: 56px; padding: 0 clamp(20px, 3vw, 32px); font-size: clamp(1rem, 1.6vw, 1.15rem); }

/* ---------------------------------------------------------------- topbar -- */
/* Solid console shell, not a glass bar. Hidden over the hero, then slides in. */

.topbar {
  position: fixed; inset: 0 0 auto;
  z-index: var(--z-topbar);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding: var(--s-3) clamp(1rem, 4vw, 2.5rem);
  background: var(--shell);
  border-bottom: var(--bw) solid var(--ink);
}
.js .topbar { transform: translateY(-101%); transition: transform .38s var(--ease-out-quint); }
.js .topbar.is-in { transform: none; }

.topbar__brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; }
.topbar__brand img { width: 30px; height: 30px; }
.topbar__brand span {
  font-family: var(--pixel); font-weight: 700; font-size: 1.02rem;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink);
}

/* ----------------------------------------------------------------- folds -- */

.fold { position: relative; }
.fold--paper { background: var(--page); padding-block: var(--fold-y); }
.fold--ink   { background: var(--ink-surface); color: var(--on-ink); padding-block: var(--fold-y); }

.fold--scene {
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  min-height: min(96svh, 900px);
  padding-block: clamp(88px, 13vw, 150px);
  background: var(--ink-surface);
  color: var(--on-ink);
}

.fold__head { max-width: 46ch; margin-bottom: clamp(var(--s-6), 5vw, var(--s-8)); }
.fold__head .lead { margin-top: var(--s-4); }
.fold__inner { position: relative; z-index: var(--z-content); max-width: 44ch; }
.fold__inner--right { margin-left: auto; }

/* Scene folds are ink islands: console.css already re-declares the on-ink trio
   for .ink, so borrow it rather than restating every colour here. */
.fold--scene, .fold--ink { --fill: var(--ink-surface); --edge: var(--on-ink-muted); }
.fold--scene :is(h1,h2,h3,strong,b), .fold--ink :is(h1,h2,h3,strong,b) { color: var(--on-ink); }
.fold--ink :is(p,li,dd,.lead,.muted,.small) { color: var(--on-ink-muted); }
.fold--scene .accent, .fold--ink .accent { color: var(--on-ink-accent); }
.fold--scene .btn--cta { --fill: var(--on-ink); color: var(--ink-surface); box-shadow: none; }

/* Copy sitting ON the art is near-white, not the muted grey used on flat ink.
   The arithmetic, worst case (a near-white window pixel behind the text):
   muted #A8A8B4 needs the scrim at ~0.85 alpha to clear 4.5:1, which blacks
   out the room; near-white needs ~0.64, which the scrim below delivers while
   the room still reads. Brighten the text, don't kill the art. The shadow is
   belt-and-braces for the brightest pixels. */
.fold--scene :is(p, li, dd, .lead) { color: rgba(242, 242, 246, .9); }
.fold--scene :is(.muted, .small) { color: rgba(242, 242, 246, .72); }
.fold--scene :is(h1, h2, .lead) { text-shadow: 0 1px 18px rgba(10, 10, 12, .55); }
/* ...but the day panel is an opaque cream surface, so it opts back out of both. */
.fold--scene .day :is(p, li, b, i, span) { color: var(--ink); text-shadow: none; }
/* The completion banner is the one thing inside the panel that isn't ON the
   panel: it's a brand-filled block and carries its own label colour. Without
   this it inherited the rule above and rendered light-on-light at 2.14:1. */
.fold--scene .day :is(.day__done, .day__done span) { color: var(--on-brand); }
.fold--scene .day .day__payout,
.fold--scene .day .day__payout span { color: var(--on-brand); }

/* ------------------------------------------------------------ scene media -- */

.scene-media { position: absolute; inset: 0; z-index: var(--z-scene); pointer-events: none; }
.scene-art { width: 100%; height: 100%; object-fit: cover; object-position: center bottom; }

/* a single character standing on the room's own floor line */
.scene-actor {
  position: absolute;
  bottom: 12%;
  right: 8%;
  height: 46%;
  width: auto;
}
/* a row of them. Definite height on the row is load-bearing: a percentage
   height on the images against an auto-height parent is indeterminate, and
   each character falls back to its intrinsic 400px and blows out of the room. */
.scene-cast {
  position: absolute;
  left: 6%; right: 6%; bottom: 11%;
  height: 46%;
  display: flex; align-items: flex-end; justify-content: center;
  gap: clamp(4px, 3%, 28px);
}
.scene-cast img {
  height: 100%; width: auto; max-width: 31%;
  object-fit: contain; object-position: bottom center;
}

/* The scrim does three jobs at once: it seams the fold into its neighbours top
   and bottom, and it darkens the side the copy sits on so body text clears AA
   over the art. Keep all three gradients; dropping the directional one is what
   makes overlaid copy unreadable at some viewport widths. */
/* The directional band holds ~0.86 across the whole text column before it
   tapers, which is what buys the contrast computed above. Narrowing it is how
   overlaid copy quietly stops clearing AA at some viewport widths. */
.scene-scrim {
  position: absolute; inset: 0; z-index: var(--z-scrim);
  background:
    linear-gradient(180deg, var(--ink-surface) 0%, rgba(28,29,35,.55) 12%, rgba(28,29,35,0) 30%),
    linear-gradient(0deg,   var(--ink-surface) 0%, rgba(28,29,35,.86) 16%, rgba(28,29,35,.35) 38%, rgba(28,29,35,0) 60%),
    linear-gradient(90deg,  rgba(28,29,35,.94) 0%, rgba(28,29,35,.88) 42%, rgba(28,29,35,.5) 64%, rgba(28,29,35,0) 86%);
}
.scene-scrim--right {
  background:
    linear-gradient(180deg, var(--ink-surface) 0%, rgba(28,29,35,.55) 12%, rgba(28,29,35,0) 30%),
    linear-gradient(0deg,   var(--ink-surface) 0%, rgba(28,29,35,.86) 16%, rgba(28,29,35,.35) 38%, rgba(28,29,35,0) 60%),
    linear-gradient(270deg, rgba(28,29,35,.94) 0%, rgba(28,29,35,.88) 42%, rgba(28,29,35,.5) 64%, rgba(28,29,35,0) 86%);
}
/* The pinned fold holds copy on the left and the panel on the right, so it
   needs the vertical wash for the seams AND a left band for the heading and
   the running note, same as the other scenes. */
.scene-scrim--even {
  background:
    linear-gradient(180deg, var(--ink-surface) 0%, rgba(28,29,35,.72) 14%, rgba(28,29,35,.5) 34%),
    linear-gradient(0deg,   var(--ink-surface) 0%, rgba(28,29,35,.88) 18%, rgba(28,29,35,.55) 46%),
    linear-gradient(90deg,  rgba(28,29,35,.86) 0%, rgba(28,29,35,.78) 40%, rgba(28,29,35,.38) 62%, rgba(28,29,35,.2) 100%);
}

/* ------------------------------------------------------------------ hero -- */

.hero { align-items: center; min-height: min(100svh, 980px); }
.hero__wrap { position: relative; z-index: var(--z-content); }

/* Measure per element, in each element's OWN font size. A single `max-width:
   40ch` on the column resolves `ch` against the column's 17px body size, which
   handed a 64px headline a ~320px box and wrapped it to five ragged lines. */
.hero__inner { max-width: min(46rem, 100%); }

.wordmark {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: var(--s-5);
  font-family: var(--pixel); font-weight: 700;
  font-size: clamp(1rem, 2.2vw, 1.2rem);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--on-ink);
}
.wordmark .orb {
  width: 20px; height: 20px; flex: none; border-radius: 50%;
  background: radial-gradient(circle at 32% 30%, var(--glow), var(--brand) 62%);
  border: 2px solid var(--on-ink);
}

/* 18ch clears the longest forced line ("keep the streak.") at every step of the
   clamp, so the three-line beat set by the <br>s is what actually renders. */
.hero h1 {
  font-size: clamp(2.3rem, 6.4vw, 4.4rem);
  line-height: 1.06;
  max-width: 18ch;
  /* console.css balances h1/h2; here the <br>s already set the beat, and
     balancing on top of hard breaks just re-ragged them. Never nowrap: the
     smallest step of the clamp has to be free to wrap rather than overflow. */
  text-wrap: wrap;
}
.hero .lead { margin-top: var(--s-5); max-width: 40ch; }

.cta { margin-top: clamp(var(--s-6), 4vw, var(--s-7)); }
.cta__note {
  margin-top: var(--s-3);
  font-family: var(--sans); font-size: .86rem; letter-spacing: .02em;
  color: var(--on-ink-muted);
}
.fold--paper .cta__note { color: var(--muted); }

/* Anchored to the content grid, not the viewport bezel. Pinned to the bezel it
   drifted away from everything on a wide screen and read as loose debris. */
/* Top of the column, not the bottom: the character is anchored to the floor and
   occupies the lower ~60% of the fold, so a bottom-right HUD lands on its chest. */
.hero__hud {
  position: absolute; z-index: var(--z-content);
  right: 0; top: 0;
  display: grid; justify-items: stretch; gap: var(--s-2);
}
.hud-chip {
  display: flex; align-items: center; gap: 8px;
  min-width: 11ch;
  padding: 8px 12px;
  background: var(--hud);
  border: var(--bw) solid var(--ink);
  color: var(--ink);
  font-family: var(--sans); font-weight: 600; font-size: .76rem;
  letter-spacing: .06em; text-transform: uppercase;
}
.hud-chip img { height: 15px; width: auto; flex: none; }
.hud-chip b { font-size: .95rem; font-weight: 700; }
.hud-chip--lvl { background: var(--brand); border-color: var(--ink); color: var(--on-brand); justify-content: center; }

/* Below this the copy column and the HUD would collide, and the character is
   already the thing carrying the fold. */
@media (max-width: 1100px) { .hero__hud { display: none; } }

/* ------------------------------------------------------------- statement -- */

.statement { padding-block: clamp(96px, 15vw, 190px); }
.statement__text {
  font-family: var(--pixel); font-weight: 700;
  font-size: clamp(1.75rem, 4.6vw, 3.1rem);
  line-height: 1.22; letter-spacing: 0;
  text-transform: lowercase;
  color: var(--on-ink);
  max-width: 22ch; text-wrap: pretty;
}
.statement__text em { font-style: normal; color: var(--on-ink-accent); }

/* Lit is the DEFAULT. Script opts into dimming, so a headless render or a
   background tab still shows the sentence rather than a blank fold. */
.statement__w { transition: color .45s var(--ease-out-quart); }
.js .statement.is-scripted .statement__w { color: rgba(232,232,237,.28); }
.js .statement.is-scripted .statement__w.is-lit { color: var(--on-ink); }
.js .statement.is-scripted .statement__text em .statement__w.is-lit { color: var(--on-ink-accent); }

.statement__proof {
  display: flex; flex-wrap: wrap; gap: clamp(var(--s-4), 3vw, var(--s-6));
  margin-top: clamp(var(--s-7), 6vw, var(--s-9));
}
.figure { flex: 1 1 200px; border-top: var(--bw) solid var(--on-ink-muted); padding-top: var(--s-4); }
.figure b {
  display: block;
  font-size: clamp(2rem, 4.4vw, 2.9rem); line-height: 1; font-weight: 700;
  color: var(--on-ink-accent);
}
.figure i {
  display: block; margin-top: var(--s-3); font-style: normal;
  font-family: var(--sans); font-size: .95rem; line-height: 1.45;
  color: var(--on-ink-muted);
}
.statement__foot { margin-top: clamp(var(--s-6), 4vw, var(--s-7)); max-width: 62ch; }
/* ------------------------------------------------- the app's own words -- */
/* Every string in one of these is lifted verbatim from the app or from the
   push payloads in the backend. They are set as UI fragments rather than in
   quote marks so they read as the thing itself, not as a claim about it.
   If the app's copy changes, these are wrong: they are quotes, not paraphrase.

   Two shapes. `.appsays` is an inline line of in-app copy. `.appsays--push`
   is a notification, with the app icon and a title over a body. */

.appsays {
  --says-edge: var(--muted);
  --says-fill: rgba(32, 32, 42, .05);
  --says-ink: var(--text);
  display: block;
  margin: var(--s-4) 0 0;
  padding: var(--s-3) var(--s-4);
  background: var(--says-fill);
  border: var(--bw) solid var(--says-edge);
  color: var(--says-ink);
  font-family: var(--sans);
  font-size: .95rem;
  line-height: 1.5;
  max-width: 52ch;
}
:is(.fold--scene, .fold--ink) .appsays {
  --says-edge: var(--on-ink-muted);
  --says-fill: rgba(232, 232, 237, .1);
  --says-ink: var(--on-ink);
}

.appsays--push {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3);
}
.appsays--push img { width: 30px; height: 30px; flex: none; }
.appsays--push b { display: block; font-weight: 700; font-size: .95rem; }
.appsays--push span { display: block; margin-top: 1px; opacity: .82; }

/* Inline inside a running sentence rather than a block of its own.
   inline-block, not inline: a bordered inline box splits its border across
   every wrapped line, so the quote came apart mid-sentence. As a block box the
   border wraps the whole quote and the chip moves to the next line intact.
   max-width keeps it from overrunning the column when the line is long. */
.appsays--inline {
  display: inline-block;
  margin: 0; padding: 2px 8px;
  font-size: .94em; max-width: 100%;
  vertical-align: baseline;
}

/* ------------------------------------------------- 03 · the scrubbed day -- */
/* A tall runway pins the room while scroll advances one day. --p (0..1) and
   data-phase are written by landing.js; every rule below reads them, so the
   fold has exactly one source of truth for "how far through the day are we". */

/* overflow:visible is load-bearing. `.fold--scene` sets `overflow: hidden`, and
   an ancestor with a clipping overflow silently breaks `position: sticky` on a
   descendant: the panel just scrolls away and leaves the rest of the runway as
   a blank screen. The clipping the scenes need happens on `.scrub__sticky`. */
.scrub { display: block; padding: 0; min-height: 0; align-items: stretch; overflow: visible; }
/* Six beats need runway. Roughly 65vh of scroll each: long enough that a beat
   registers before the next one lands, short enough not to feel stuck. */
.scrub__shell { min-height: 400vh; }
.scrub__sticky {
  position: sticky; top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex; align-items: center;
  background: var(--ink-surface);
}
.scrub__inner {
  position: relative; z-index: var(--z-content);
  display: grid;
  gap: clamp(var(--s-5), 4vw, var(--s-7));
  align-items: center;
}
@media (min-width: 900px) { .scrub__inner { grid-template-columns: 0.85fr 1fr; } }

.scrub__head h2 { font-size: clamp(1.9rem, 4.4vw, 3rem); }
.scrub__head .lead { margin-top: var(--s-4); }

/* the console panel */
.day {
  --fill: var(--hud);
  background: var(--hud);
  border: var(--bw) solid var(--ink);
  box-shadow: var(--sh) var(--sh) 0 var(--ink);
  padding: clamp(var(--s-4), 2.4vw, var(--s-5));
  color: var(--ink);
  display: grid; gap: var(--s-4);
}
.day :is(b, i, span, p, li) { color: var(--ink); }

.day__hud { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); }
.day__meter { flex: 1 1 220px; min-width: 0; }
.day__meter-label,
.day__stat i {
  font-family: var(--sans); font-weight: 600; font-size: .68rem;
  letter-spacing: .08em; text-transform: uppercase; opacity: .75;
}
.day__track {
  display: block; height: 14px; margin-top: 6px;
  background: var(--track);
  border: var(--bw) solid var(--ink);
  overflow: hidden;
}
.day__fill {
  display: block; height: 100%;
  width: calc(var(--xp, 0) * 100%);
  background: var(--brand);
  transition: width .4s var(--ease-out-quint);
}
.day__meter-val { display: block; margin-top: 5px; font-family: var(--sans); font-size: .82rem; }
.day__meter-val b { font-weight: 700; }
.day__stats { display: flex; gap: var(--s-3); }
.day__stat {
  display: grid; grid-template-columns: auto auto; grid-template-rows: auto auto;
  gap: 0 6px; align-items: center;
  padding: 6px 11px; background: var(--stage);
  border: var(--bw) solid var(--ink);
}
.day__stat img { grid-row: span 2; height: 17px; width: auto; }
.day__stat b { font-size: 1.05rem; font-weight: 700; line-height: 1.1; }
.day__stat i { grid-column: 2; }

/* dose rows */
.day__rows { list-style: none; display: grid; gap: var(--s-2); margin: 0; padding: 0; }
.dose {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3);
  background: var(--card);
  border: var(--bw) solid var(--ink);
  transition: opacity .3s var(--ease-out-quart), background .3s var(--ease-out-quart);
}
.dose__tick {
  flex: none; width: 22px; height: 22px;
  background: var(--page);
  border: var(--bw) solid var(--ink);
  position: relative;
}
.dose__tick::after {
  content: ""; position: absolute; inset: 3px 4px 5px 4px;
  border-left: 3px solid var(--on-brand); border-bottom: 3px solid var(--on-brand);
  transform: rotate(-45deg) scale(.4); opacity: 0;
  transition: transform .28s var(--ease-out-quint), opacity .18s linear;
}
.dose__body { flex: 1; min-width: 0; display: grid; }
.dose__body b { font-family: var(--sans); font-weight: 650; font-size: 1rem; }
.dose__body i {
  font-style: normal; font-family: var(--sans); font-size: .82rem;
  letter-spacing: .03em; opacity: .7;
}
.dose__cta {
  flex: none; padding: 5px 12px;
  background: var(--cta); color: var(--on-cta);
  border: var(--bw) solid var(--ink);
  font-family: var(--pixel); font-weight: 700; font-size: .9rem;
  letter-spacing: .06em; text-transform: uppercase;
  transition: opacity .2s linear;
}
/* Armed: the beat before the tap lands. The row lifts and its button reads as
   pressed, so the sequence looks operated rather than toggled. */
.dose { transform: translateZ(0); }
.dose.is-armed {
  background: var(--stage);
  box-shadow: 0 0 0 2px var(--brand);
}
.dose.is-armed .dose__cta { background: var(--cta-bevel); transform: translate(1px, 1px); }

.dose.is-done { background: var(--stage); }
.dose.is-done .dose__tick { background: var(--brand); }
.dose.is-done .dose__tick::after { transform: rotate(-45deg) scale(1); opacity: 1; }
.dose.is-done .dose__cta { opacity: 0; }
.dose.is-done .dose__body { opacity: .62; }

/* The payout. Fires once, on the way in, when the day completes. */
.day__stat--coin { position: relative; }
.day__payout {
  position: absolute; left: 50%; bottom: 100%;
  translate: -50% 0;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 9px; margin-bottom: 6px;
  white-space: nowrap;
  background: var(--brand); color: var(--on-brand);
  border: var(--bw) solid var(--ink);
  font-family: var(--sans); font-weight: 700; font-size: .82rem;
  opacity: 0; pointer-events: none;
}
.day__payout img { height: 13px; width: auto; }
.scrub.is-paying .day__payout { animation: coin-pop 1.1s var(--ease-out-quint) both; }
.scrub.is-paying .day__stat--coin { animation: coin-bump .5s var(--ease-out-quint); }

@keyframes coin-pop {
  0%   { opacity: 0; transform: translateY(10px) scale(.85); }
  22%  { opacity: 1; transform: translateY(0) scale(1); }
  70%  { opacity: 1; transform: translateY(-4px) scale(1); }
  100% { opacity: 0; transform: translateY(-16px) scale(.96); }
}
@keyframes coin-bump {
  0%, 100% { transform: none; }
  40%      { transform: translateY(-4px); }
}

.day__done {
  margin: 0;
  font-family: var(--pixel); font-weight: 700;
  font-size: clamp(.95rem, 2vw, 1.15rem);
  letter-spacing: .08em; text-transform: uppercase;
  text-align: center;
  padding: var(--s-3);
  background: var(--brand); color: var(--on-brand);
  border: var(--bw) solid var(--ink);
}
.day__done span { color: var(--on-brand); }
.js .scrub .day__done { opacity: 0; transform: translateY(6px); transition: opacity .3s linear, transform .35s var(--ease-out-quint); }
.js .scrub[data-phase="5"] .day__done { opacity: 1; transform: none; }

/* the running commentary, one note per phase */
/* The notes stack on top of each other, so the box has to be as tall as the
   tallest one: they carry quoted app copy now, which runs to three lines. */
.scrub__notes { list-style: none; margin: var(--s-5) 0 0; padding: 0; position: relative; min-height: 5.4em; }
.scrub__notes li {
  font-family: var(--sans); font-size: .98rem; line-height: 1.5;
  color: var(--on-ink-muted); max-width: 46ch;
}
.js .scrub__notes li {
  position: absolute; inset: 0 auto auto 0;
  opacity: 0; transform: translateY(6px);
  transition: opacity .3s linear, transform .35s var(--ease-out-quint);
}
.js .scrub__notes li.is-on { opacity: 1; transform: none; }

/* -------------------------------------------------------------- 04 holds -- */

.holds__grid {
  display: grid; gap: clamp(var(--s-5), 3vw, var(--s-7));
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  padding-bottom: clamp(var(--s-6), 5vw, var(--s-8));
  border-bottom: var(--bw) solid var(--ink);
}
.pillar h3 {
  font-family: var(--pixel); font-weight: 700; font-size: 1.5rem;
  text-transform: lowercase; letter-spacing: .02em;
  margin-bottom: var(--s-3);
  color: var(--brand-text);
}
.pillar p { color: var(--text-soft); }

.ledger {
  list-style: none; margin: clamp(var(--s-6), 5vw, var(--s-8)) 0 0; padding: 0;
  display: grid; gap: var(--s-3) var(--s-7);
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.ledger li {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 1rem; color: var(--text-soft);
}
.ledger li::before {
  content: ""; flex: none; width: 9px; height: 9px; margin-top: .5em;
  background: var(--brand);
}

/* ------------------------------------------------------------- 05 avatar -- */

.avatar { align-items: center; }
.avatar h2, .clans h2 { font-size: clamp(1.9rem, 4.6vw, 3.1rem); }
.avatar .lead, .clans .lead { margin-top: var(--s-4); }

.steps { list-style: none; margin: clamp(var(--s-5), 3vw, var(--s-6)) 0 0; padding: 0; display: grid; gap: var(--s-3); }
.steps li { display: flex; align-items: flex-start; gap: var(--s-3); font-size: 1rem; }
.steps__n {
  flex: none; width: 26px; height: 26px;
  display: grid; place-items: center;
  background: var(--brand); color: var(--on-brand);
  font-weight: 700; font-size: .88rem;
}


/* -------------------------------------------------------------- 06 clans -- */

.clans { align-items: center; }
.facts { margin: clamp(var(--s-5), 3vw, var(--s-6)) 0 var(--s-5); display: grid; gap: var(--s-4) var(--s-6); }
@media (min-width: 560px) { .facts { grid-template-columns: 1fr 1fr; } }
.facts dt {
  font-family: var(--pixel); font-weight: 700; font-size: 1.05rem;
  letter-spacing: .04em; text-transform: lowercase;
  color: var(--on-ink);
}
.facts dd { margin: 4px 0 0; font-size: .95rem; }

/* ------------------------------------------------------------ 07 pricing -- */

.plans { display: grid; gap: clamp(var(--s-5), 3vw, var(--s-6)); align-items: start; }
@media (min-width: 820px) { .plans { grid-template-columns: 1fr 1.1fr; } }

.plan {
  background: var(--card);
  border: var(--bw) solid var(--ink);
  padding: clamp(var(--s-5), 3vw, var(--s-6));
}
.plan--pro { box-shadow: var(--sh) var(--sh) 0 var(--ink); }
.plan__art { display: block; width: 100%; max-width: 380px; margin: 0 0 var(--s-3) -6px; }
.plan h3 { font-size: 1.15rem; }
.plan__price { display: flex; align-items: baseline; gap: 8px; margin: var(--s-1) 0 var(--s-2); }
.plan__price b { font-size: clamp(2rem, 4vw, 2.6rem); line-height: 1; font-weight: 700; color: var(--brand-text); }
.plan__price span { font-size: .95rem; font-weight: 600; color: var(--muted); }
.plan__sub { font-size: .95rem; color: var(--muted); margin-bottom: var(--s-5); }
.plan ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-3); }
.plan li { display: flex; align-items: flex-start; gap: 10px; font-size: 1rem; color: var(--text-soft); }
.plan li::before {
  content: ""; flex: none; width: 9px; height: 9px; margin-top: .5em;
  background: var(--brand);
}
.plans__terms { margin-top: clamp(var(--s-5), 3vw, var(--s-6)); max-width: 74ch; }

/* --------------------------------------------------------------- 08 faq -- */
/* `<details name="faq">` gives an exclusive accordion natively: opening one
   closes the rest, with no script and no ARIA to keep in sync. */

.faq__grid { display: grid; gap: clamp(var(--s-6), 5vw, var(--s-8)); align-items: start; }
@media (min-width: 900px) { .faq__grid { grid-template-columns: 0.8fr 1.2fr; } }
.faq .fold__head { margin-bottom: 0; }
.faq__list { display: grid; gap: var(--s-2); }

.faq details {
  background: var(--card);
  border: var(--bw) solid var(--ink);
}
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding: var(--s-4);
  cursor: pointer; list-style: none;
  font-family: var(--sans); font-weight: 620; font-size: 1.02rem;
  color: var(--text);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 11px; height: 11px;
  border-right: 2.5px solid var(--ink); border-bottom: 2.5px solid var(--ink);
  rotate: 45deg; translate: 0 -3px;
  transition: rotate .18s var(--ease-out-quart), translate .18s var(--ease-out-quart);
}
.faq details[open] summary::after { rotate: 225deg; translate: 0 2px; }
.faq details[open] summary { color: var(--brand-text); }
.faq__a { padding: 0 var(--s-4) var(--s-4); display: grid; gap: var(--s-3); }
.faq__a p { font-size: .98rem; color: var(--text-soft); max-width: 62ch; }
.faq a { color: var(--brand-text); font-weight: 600; }

/* ---------------------------------------------------------- 09 fineprint -- */
/* The quietest surface on the page. No game chrome anywhere near it. */

.fineprint { padding-block: clamp(var(--s-7), 7vw, var(--s-9)); border-top: var(--bw) solid var(--ink); }
.fineprint__h {
  font-family: var(--sans); font-weight: 650; font-size: .82rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
  margin-bottom: var(--s-5);
}
.fineprint__rows { display: grid; gap: var(--s-4) var(--s-7); }
@media (min-width: 760px) { .fineprint__rows { grid-template-columns: 1fr 1fr; } }
.fineprint p { font-size: .94rem; line-height: 1.55; color: var(--muted); max-width: none; }
.fineprint strong { color: var(--text-soft); font-weight: 650; }

/* ----------------------------------------------------------- 09 download -- */

.download { align-items: center; text-align: center; }
.download__inner { position: relative; z-index: var(--z-content); max-width: 34ch; margin-inline: auto; }
.download h2 { font-size: clamp(2rem, 5.4vw, 3.4rem); margin-top: var(--s-4); }
.download .lead { margin-top: var(--s-4); margin-inline: auto; }
.download .cta__note { text-align: center; }
.download .readout { color: var(--on-ink-accent); }
.download .scene-actor { right: auto; left: 50%; translate: -50% 0; bottom: 6%; height: 30%; opacity: .55; }

/* ------------------------------------------------------------ site footer -- */

.siteftr { background: var(--shell); border-top: var(--bw) solid var(--ink); }
.siteftr__in {
  display: grid; gap: var(--s-6);
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  padding-block: clamp(var(--s-6), 5vw, var(--s-8));
}
.siteftr__brand p { margin-top: var(--s-3); font-size: .95rem; color: var(--text-soft); max-width: 42ch; }
.siteftr__col h3 {
  font-family: var(--sans); font-weight: 650; font-size: .8rem;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  margin-bottom: var(--s-3);
}
.siteftr__col a { display: block; padding: 6px 0; font-size: .96rem; text-decoration: none; color: var(--text); }
.siteftr__col a:hover { color: var(--brand-text); }
.siteftr__base {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s-2) var(--s-5);
  border-top: var(--bw) solid var(--ink);
  padding-block: var(--s-4);
  font-size: .86rem; color: var(--muted);
}

/* ---------------------------------------------------------------- motion -- */
/* Three earned moments and two real lists. Nothing else moves on scroll. */

@keyframes rise-in {
  from { opacity: 0; filter: blur(9px); transform: translate3d(0, 16px, 0); }
  to   { opacity: 1; filter: blur(0);   transform: none; }
}

.js .hero .seq { opacity: 0; }
.js .hero.is-ready .seq {
  animation: rise-in .8s var(--ease-out-quint) both;
  animation-delay: calc(80ms + var(--i) * 110ms);
}

.js [data-stagger] > * { opacity: 0; transform: translateY(10px); }
.js [data-stagger].is-in > * {
  animation: rise-in .55s var(--ease-out-quart) both;
  animation-delay: calc(var(--i) * 55ms);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    transition-duration: .001ms !important;
  }
  .js .hero .seq,
  .js [data-stagger] > * { opacity: 1; transform: none; filter: none; }
  .js .statement.is-scripted .statement__w { color: var(--on-ink); }
  .js .statement.is-scripted .statement__text em .statement__w { color: var(--on-ink-accent); }

  /* No runway, no pin: the day shows its finished state as a static panel. */
  .scrub__shell { min-height: 0; }
  .scrub__sticky { position: static; height: auto; padding-block: var(--fold-y); }
  .js .scrub .day__done { opacity: 1; transform: none; }
  .js .scrub__notes li { position: static; opacity: 1; transform: none; }
  .scrub__notes { min-height: 0; display: grid; gap: var(--s-3); }
  .js .topbar { transform: none; }
  .day__payout { display: none; }
}

/* ------------------------------------------------------------ responsive -- */

@media (max-width: 900px) {
  .fold--scene { min-height: 0; padding-block: clamp(64px, 12vw, 96px); }
  /* margin-inline, NOT margin-left:0. These elements are also `.wrap`, which
     centres itself with auto margins to make the gutters; zeroing the left one
     pinned the avatar and clans copy flush to the screen edge and stacked the
     whole gutter on the right. */
  .fold__inner, .fold__inner--right { max-width: none; margin-inline: auto; }

  /* The hero stacks rather than composes: at this width the copy runs the full
     column, so a bottom-right character anchored at 46% lands underneath the
     paragraph. Copy takes the top half, the character keeps the floor. */
  .hero {
    align-items: flex-start;
    /* .fold--scene drops min-height at this width; the hero has to put it back,
       or the fold shrink-wraps the copy and the character lands on top of it
       again with nowhere else to stand. */
    min-height: min(100svh, 900px);
    padding-top: clamp(92px, 17vh, 132px);
    /* Reserved floor for the character, in the SAME unit as its height, so the
       two can't drift apart on a shorter phone. Percentages would be measured
       against a fold that grows with its own copy, which is circular. */
    padding-bottom: 30svh;
  }
  .hero .scene-actor { height: 27svh; right: 4%; bottom: 0; }
  .hero .lead { max-width: none; }
  /* Stacked, the two needs invert: the copy now spans the FULL column (a
     left-weighted band leaves line-ends over the bright window) while the
     character owns the bottom band and gets swallowed by a full-strength seam.
     So the mobile scrim runs vertically instead: heavy over the copy band,
     easing off over the floor the character stands on. */
  .hero .scene-scrim {
    background: linear-gradient(180deg,
      var(--ink-surface) 0%,
      rgba(28,29,35,.9) 10%,
      rgba(28,29,35,.88) 68%,
      rgba(28,29,35,.5) 80%,
      rgba(28,29,35,.34) 100%);
  }

  /* On a phone the room becomes a band above the copy rather than a bed under
     it: overlaying a paragraph on a 5:3 room at 390px wide can't hold AA.
     Named folds, not a :not() chain — an earlier version of this rule also
     caught the pinned fold and pushed its panel out of the sticky viewport. */
  .avatar, .clans { display: block; padding-top: 0; }
  .avatar .scene-media, .clans .scene-media {
    position: relative; inset: auto;
    height: clamp(200px, 54vw, 320px);
    margin-bottom: clamp(var(--s-5), 6vw, var(--s-6));
  }
  .avatar .scene-scrim, .clans .scene-scrim {
    background:
      linear-gradient(180deg, var(--ink-surface) 0%, rgba(28,29,35,.4) 16%, rgba(28,29,35,0) 40%),
      linear-gradient(0deg,   var(--ink-surface) 0%, rgba(28,29,35,.5) 22%, rgba(28,29,35,0) 55%);
  }
  .avatar .scene-cast, .clans .scene-cast { height: 62%; bottom: 8%; }

  .scrub__shell { min-height: 360vh; }
  .scrub__sticky { align-items: flex-start; padding-top: clamp(72px, 14vh, 108px); }
  .scrub__inner { align-content: start; }
  .scrub__notes { min-height: 7.4em; }
}

@media (max-width: 560px) {
  .day__stats { width: 100%; }
  .day__stat { flex: 1; }
  .hero h1 { font-size: clamp(2rem, 9vw, 2.8rem); }
}

/* A pinned fold is the one place where viewport HEIGHT, not width, decides
   whether the design fits: the sticky pane can't grow, so on a short laptop
   or a landscape phone the panel has to give up size rather than be clipped. */
@media (max-height: 720px) and (min-width: 900px) {
  .scrub__head h2 { font-size: clamp(1.5rem, 3vw, 2rem); }
  .scrub__head .lead { font-size: 1rem; }
  .day { padding: var(--s-4); gap: var(--s-3); }
  .dose { padding: var(--s-2) var(--s-3); }
  .scrub__notes { margin-top: var(--s-4); }
}
@media (max-height: 620px) {
  .scrub__head .lead { display: none; }
  .day__meter-val { display: none; }
}
/* Below this there is no pane left to pin against, so stop pretending: the
   fold unpins into an ordinary panel and the script renders the finished day. */
@media (max-height: 520px) {
  .scrub__shell { min-height: 0; }
  .scrub__sticky {
    position: static; height: auto; overflow: visible;
    padding-block: var(--fold-y);
  }
  .js .scrub__notes li { position: static; opacity: 1; transform: none; }
  .scrub__notes { min-height: 0; display: grid; gap: var(--s-3); }
  .js .scrub .day__done { opacity: 1; transform: none; }
}
