/* nestshell marketing site — the Field climate.
 *
 * Tokens mirror app/lib/core/theme/app_theme.dart and
 * design/prototype-v2/src/styles.css. Do NOT introduce the in-app Material
 * indigo (#4F6EF7) or Inter; those belong to specs/DESIGN.md, not here.
 */

:root{
  --paper:#FBF7F0;          /* AppTheme.paper / --paper-solid */
  --ink:#3D3125;            /* all text under 18pt lives here */
  --ink-soft:#3D3125D1;     /* ~0.82 alpha, 6.8:1. NOT the prototype's 0.62 (3.8:1, fails AA) */
  --gold:#E6B574;           /* AppTheme.gold */
  --gold-deep:#C8943F;      /* AppTheme.goldDeep — 2.5:1 on paper, so DECORATIVE ONLY (ring, rules) */
  --gold-ink:#916A2A;       /* same hue darkened to 4.6:1 — the gold that small text may use */
  --seal:#B8322C;           /* AppTheme.sealRed */
  --seal-hover:#C43A34;     /* pill hover. kami's own #CF4A43 is 4.36:1 on ivory, under AA */
  --ivory:#FFFCF8;          /* pill label, 5.8:1 on --seal */
  --line:rgba(90,70,40,.14);

  /* Source Serif 4 is not subset into www/fonts yet — see fonts/README.md.
     Until it is, this stack is the fallback the doc specifies. */
  --serif:"Source Serif 4","Iowan Old Style","Palatino Linotype",Palatino,"Songti SC",Georgia,serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --code-bg:#F2ECE1;

  color-scheme:light;
}

html.theme-dark,
:root[data-theme="dark"]{
  --paper:#23212C;
  --ink:#ECE6DA;
  --ink-soft:#ECE6DACF;   /* ~0.81 alpha, AA on dusk */
  --gold-ink:#E6B574;     /* #916A2A fails on dusk */
  --line:rgba(236,230,218,.14);
  --code-bg:rgba(236,230,218,.1);
  color-scheme:dark;
}

*{box-sizing:border-box}
html,body{margin:0}
html{-webkit-text-size-adjust:100%}

html,body{
  background:var(--paper);
  color:var(--ink);
}
body{
  font-family:var(--serif);
  font-size:clamp(1rem,.4vw + .9rem,1.125rem);
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
}

/* focus is --ink, not --gold-deep: gold on paper is 2.5:1 and fails the 3:1
   that WCAG 1.4.11 asks of a focus indicator. */
:focus-visible{outline:2px solid var(--ink);outline-offset:3px;border-radius:2px}
:focus:not(:focus-visible){outline:none}

.skip{
  position:absolute;left:-9999px;top:0;z-index:99;
  background:var(--paper);color:var(--ink);
  padding:12px 18px;border:1px solid var(--ink);border-radius:4px;
  font-family:var(--mono);font-size:13px;text-decoration:none;
}
.skip:focus{left:16px;top:16px}

/* ---------------- chrome ---------------- */
.site-header{
  display:flex;align-items:center;flex-wrap:wrap;gap:10px 14px;
  padding:20px clamp(18px,5vw,56px);
  border-bottom:1px solid var(--line);
}
.mark{width:32px;height:32px;border-radius:7px;display:block}
.mark--dark{display:none}
html.theme-dark .mark--light,
:root[data-theme="dark"] .mark--light{display:none}
html.theme-dark .mark--dark,
:root[data-theme="dark"] .mark--dark{display:block}
.wordmark{font-size:18px;letter-spacing:-.01em;color:inherit;text-decoration:none}
.theme-toggle{
  margin-left:auto;
  display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:44px;padding:0;
  border:1px solid var(--line);border-radius:4px;
  background:transparent;color:var(--ink);cursor:pointer;
}
.theme-toggle:hover{border-color:var(--gold-deep);color:var(--gold-ink)}
.theme-icon{width:22px;height:22px;display:block}
.theme-icon--sun{display:none}
html.theme-dark .theme-icon--sun{display:block}
html.theme-dark .theme-icon--moon{display:none}
.header-link{
  font-family:var(--mono);font-size:12px;letter-spacing:.06em;
  color:var(--ink);text-decoration:none;
  display:inline-flex;align-items:center;
  min-height:44px;padding:0 4px;
  border-bottom:1px solid var(--gold-deep);
}
.header-link:hover{border-bottom-color:var(--ink)}

.site-footer{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px 22px;
  padding:20px clamp(18px,5vw,56px) 40px;
  border-top:1px solid var(--line);
  font-family:var(--mono);font-size:11.5px;color:var(--ink);
}
.footer-links{display:flex;gap:18px;margin-left:auto}
.footer-links a{
  color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--gold-deep);
  min-height:44px;display:inline-flex;align-items:center;
}
.footer-links a:hover{border-bottom-color:var(--ink)}

/* ---------------- hero ---------------- */
.hero{padding:clamp(34px,6vw,68px) clamp(18px,5vw,56px) clamp(20px,3vw,32px);max-width:1100px;margin:0 auto}
.tagline{
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--gold-ink);margin:0 0 14px;
}
.hero h1{
  font-size:clamp(1.75rem,4vw + 1rem,3rem);
  line-height:1.1;font-weight:600;letter-spacing:-.015em;
  margin:0 0 18px;max-width:17em;
}
.lede{margin:0 0 clamp(26px,4vw,40px);max-width:33em;color:var(--ink)}
.lede a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--gold-deep)}
.lede a:hover{border-bottom-color:var(--ink)}

.stage-wrap{margin:0}

/* ---------------- stage ---------------- */
/* The stage's paint order, written down once so it is a decision and not an
   accident. Read it as: the field, then the walls, then the people, then the
   work they produce, then the words about it, then the Ask, then the close.
   Nothing that a visitor is meant to READ may sit under something that is
   painted over it, which is why the coder is 4 and not 8: at 8 the ghost that
   holds the eggs outranked the tickets, the milestone, the pinned mission and
   the ledger, so any beat that ever moved one of them under Fen would have
   hidden it with no overlap for the audit to find.

     1  .motes          drifting light
     2  .nest           the team wall and the member walls
     3  .ghost          the team
     4  .ghost.coder    the one holding the eggs, above its peers only
     6  .mission .tickets .paper-page .stack .ledger .composer   the work
     7  .layer          the beat's sentence, never covered by the work
     8  .askbox         the crossing being asked about, above everything
     9  .cta-wrap       the closing frame

   tools/www-overlap.js proves no two of these intersect; the ladder is what
   keeps that true when one of them moves. */
.stage{
  position:relative;width:100%;aspect-ratio:16/10;
  background:var(--paper);border:1px solid var(--line);border-radius:6px;
  overflow:hidden;isolation:isolate;
  transition:background .35s ease,color .35s ease;
}
.stage[data-climate="cosmos"]{
  --paper:#23212c;--ink:#ECE6DA;--ink-soft:rgba(236,230,218,.78);--line:rgba(236,230,218,.14);
  --gold-ink:#E6B574;     /* #916A2A is 1.8:1 on the cosmos ground */
  background:#23212c;color:#ECE6DA;
}
/* the phone stage is taller than 3:4 — see the phone block at the foot of
   this file for why, and for the bands it buys */

.motes{position:absolute;inset:0;pointer-events:none;z-index:1}
.mote{
  position:absolute;width:3px;height:3px;border-radius:50%;
  background:var(--gold);opacity:0;animation:mote 11s ease-in-out infinite;
}
@keyframes mote{
  0%{opacity:0;transform:translate(0,0) scale(.6)}
  12%{opacity:.55}
  50%{opacity:.35;transform:translate(14px,-26px) scale(1)}
  88%{opacity:.25}
  100%{opacity:0;transform:translate(-8px,-52px) scale(.7)}
}

/* nest walls — the ring path is inlined by js/site.js from img/ring.svg */
.nest{
  position:absolute;left:var(--x);top:var(--y);
  width:var(--w);aspect-ratio:1;
  transform:translate(-50%,-50%);
  color:var(--gold-deep);
  opacity:0;z-index:2;
  transition:opacity .7s ease,left .9s cubic-bezier(.4,0,.2,1),top .9s cubic-bezier(.4,0,.2,1),width .9s cubic-bezier(.4,0,.2,1);
}
.nest svg{width:100%;height:100%;display:block;overflow:visible}
.nest path{
  fill:none;stroke:currentColor;stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:2600;stroke-dashoffset:2600;opacity:.88;
}
.nest.on{opacity:1}
.nest.dim{opacity:.4}
.nest.faint{opacity:.18}
/* stroke-width is in the 800-unit viewBox, so it scales with --w: a member
   wall at 14% needs a much larger number than the team wall at 56% to land
   on the same ~2.5px on screen. */
.nest.thick path{stroke-width:5.4}
.nest--small path{stroke-width:13}
.nest.on path{animation:draw 1.3s cubic-bezier(.45,0,.2,1) forwards}
@keyframes draw{to{stroke-dashoffset:0}}

/* ghosts */
.ghost{
  position:absolute;left:var(--x);top:var(--y);
  width:var(--gw,74px);
  transform:translate(-50%,-50%) scale(0);
  opacity:0;z-index:3;
  transition:left 1s cubic-bezier(.4,0,.2,1),top 1s cubic-bezier(.4,0,.2,1),opacity .5s ease,width .7s ease;
}
.ghost.on{opacity:1;animation:pop .62s cubic-bezier(.34,1.56,.64,1) forwards}
.ghost.on.faint{opacity:.34}
@keyframes pop{
  0%{transform:translate(-50%,-50%) scale(0) rotate(-8deg)}
  55%{transform:translate(-50%,-50%) scale(1.18) rotate(3deg)}
  100%{transform:translate(-50%,-50%) scale(1) rotate(0)}
}
.ghost-float{position:relative;animation:float 4.2s ease-in-out infinite;transform-origin:50% 60%}
.ghost.coder{z-index:4}   /* above its peers, under the work — see the ladder */
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}
.ghost svg{width:100%;height:auto;display:block;filter:drop-shadow(0 6px 16px rgba(120,90,40,.16))}
/* The labels are wider than the ghost they belong to — "CAPTAIN" at 9px with
   .14em tracking is ~47px against a 34-40px shell — so they are sized to their
   own text and centred under it rather than left to overflow a narrower box.
   Visually identical; the difference is that the element's own rect now tells
   the truth about how much room the label takes, which is what the overlap
   audit in tools/www-overlap.js measures. */
.ghost-name,.ghost-role{
  width:max-content;margin-left:50%;transform:translateX(-50%);
}
.ghost-name{
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  text-align:center;margin-top:9px;color:var(--ink-soft);white-space:nowrap;
}
.ghost-role{
  font-family:var(--mono);font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  text-align:center;margin-top:3px;color:var(--gold-ink);
  opacity:0;height:0;overflow:hidden;
  transition:opacity .4s ease,height .4s ease;
}
.ghost.captain .ghost-role{opacity:1;height:1.2em}
.ghost.speaking .core{animation:coreglow 1.4s ease-in-out infinite}
@keyframes coreglow{0%,100%{opacity:.9}50%{opacity:1;transform:scale(1.09)}}
.core{transform-origin:center;transform-box:fill-box}

/* eggs pack in rows inside the shell; overflow is clipped to the oval */
.egg-belly{
  position:absolute;left:24%;width:52%;top:38%;height:42%;
  display:flex;flex-flow:row wrap;align-content:center;justify-content:center;align-items:center;
  gap:6% 5%;
  overflow:hidden;
  clip-path:ellipse(50% 50% at 50% 50%);
  pointer-events:none;opacity:0;
  transition:opacity .5s ease;
}
.ghost.coder .egg-belly{opacity:1}
.egg{
  flex:0 0 18%;
  aspect-ratio:3/4;
  height:auto;
  border-radius:50%;
  background:radial-gradient(circle at 35% 32%,#FFE9C4 0%,var(--gold) 52%,var(--gold-deep) 100%);
  box-shadow:0 0 6px rgba(230,181,116,.45);
  opacity:0;transform:scale(.35);
  transition:opacity .28s ease,transform .28s cubic-bezier(.34,1.35,.64,1);
}
.egg.in{opacity:1;transform:scale(1)}

/* ---------------- the first egg ---------------- */
/* Beat 1 is an empty field, and an empty field is not a joke. The play is one
   egg rocking where the captain will hatch: the field has nobody in it yet,
   only something about to be someone. It leaves the moment Quill pops, so
   "Empty field" still reads, and the play stays in the visual layer. */
.seed{
  position:absolute;left:var(--x,50%);top:var(--y,22%);
  width:clamp(20px,2.4vw,30px);aspect-ratio:3/4;
  transform:translate(-50%,-50%) scale(.4);
  border-radius:50%;
  background:radial-gradient(circle at 35% 32%,#FFE9C4 0%,var(--gold) 52%,var(--gold-deep) 100%);
  box-shadow:0 7px 20px rgba(200,148,63,.3);
  opacity:0;z-index:3;pointer-events:none;
  transition:opacity .45s ease,transform .5s cubic-bezier(.34,1.5,.64,1);
}
.seed.on{
  opacity:1;transform:translate(-50%,-50%) scale(1);
  animation:rock 3.6s ease-in-out .6s infinite;
}
@keyframes rock{
  0%,100%{transform:translate(-50%,-50%) rotate(-7deg)}
  50%{transform:translate(-50%,-50%) rotate(7deg)}
}

/* ---------------- the pinned mission ---------------- */
/* Written once in beat 1 and pinned for the rest of the loop: the founder
   never has to say it again, and the rule stays visible while the team works. */
.mission{
  position:absolute;left:clamp(14px,3.5%,34px);top:clamp(12px,3%,26px);
  z-index:6;max-width:min(46%,264px);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .5s ease;
}
.mission.on{opacity:1;visibility:visible}
.mission.faint{opacity:.55}
.mission-label{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--gold-ink);margin:0 0 7px;
}
.mission-line{
  margin:0 0 5px;padding-left:9px;
  border-left:2px solid var(--gold-deep);
  font-family:var(--mono);font-size:11px;line-height:1.35;color:var(--ink);
  opacity:0;transform:translateY(-4px);
  transition:opacity .35s ease,transform .35s ease;
}
.mission-line.in{opacity:1;transform:none}

/* ---------------- the Ask ---------------- */
/* The pinned rule is the culture, so a crossing shows an Ask and both
   answers stay on screen. Decline is a normal answer, not an error. */
.askbox{
  position:absolute;left:var(--x);top:var(--y);
  transform:translate(-50%,-50%) scale(.9);
  z-index:8;opacity:0;visibility:hidden;pointer-events:none;
  background:var(--paper);border:1px solid var(--line);border-radius:8px;
  padding:10px 14px 11px;box-shadow:0 10px 26px rgba(80,60,30,.14);
  transition:opacity .35s ease,transform .35s cubic-bezier(.34,1.3,.64,1);
}
.askbox.on{opacity:1;visibility:visible;transform:translate(-50%,-50%) scale(1)}
.askbox-q{margin:0 0 8px;font-family:var(--mono);font-size:11px;color:var(--ink);white-space:nowrap}
.askbox-a{margin:0;display:flex;gap:7px}
.askbox-a span{
  font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--ink);
  border:1px solid var(--line);border-radius:3px;padding:4px 9px;
  transition:color .3s ease,border-color .3s ease;
}
.askbox.answered .pick{border-color:var(--ink);font-weight:600}
/* The answer that was not taken. It stays readable on purpose: the
   storyboard shows two visible answers because "Decline is a normal
   answer", and an answer nobody can read is not an answer, it is a
   disabled control. It was opacity:.3 — 1.77:1 on paper and 2.41:1 on
   dusk, under invariant 9's 4.5:1 floor. Now --ink-soft (6.8:1 on
   paper, 8.9:1 on dusk), and the chosen answer is still obviously the
   chosen one: full ink and 600 weight inside a solid border, against
   400 weight inside a dashed one. No strike: line-through already
   means *done* on this stage (.ticket-chip.done, same mono face, same
   --ink-soft, two beats later), and one mark cannot carry two
   meanings. */
.askbox.answered .alt{
  color:var(--ink-soft);
  border-style:dashed;
}
/* The storyboard's own words for beat 2's Decline. It appears only once the
   answer is given, so the Decline is visibly answered and visibly harmless. */
.askbox-note{
  margin:8px 0 0;
  font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--ink);
  opacity:0;height:0;overflow:hidden;
  transition:opacity .35s ease,height .35s ease;
}
.askbox.answered .askbox-note{opacity:1;height:1.4em}
html.theme-dark .askbox,
:root[data-theme="dark"] .askbox{box-shadow:0 10px 26px rgba(0,0,0,.35)}

/* ---------------- tickets ---------------- */
/* Three real chips that travel member → captain → coder as one stack. */
.tickets{
  position:absolute;left:var(--x);top:var(--y);
  transform:translate(-50%,-50%);
  z-index:6;display:flex;flex-direction:column;gap:6px;
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .35s ease,
             left .7s cubic-bezier(.4,0,.2,1),
             top .7s cubic-bezier(.4,0,.2,1);
}
.tickets.on{opacity:1;visibility:visible}
.ticket-chip{
  margin:0;display:flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:11px;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);border-radius:4px;
  padding:6px 10px;white-space:nowrap;
  box-shadow:0 6px 18px rgba(80,60,30,.1);
  opacity:0;transform:translateY(6px);
  transition:opacity .3s ease,transform .3s ease,color .3s ease;
}
.ticket-chip.in{opacity:1;transform:none}
.ticket-chip::before{
  content:"";flex:0 0 12px;width:12px;height:12px;
  border:1.5px solid var(--gold-deep);border-radius:2px;box-sizing:border-box;
}
.ticket-chip.done{
  color:var(--ink-soft);text-decoration:line-through;
  text-decoration-color:var(--gold-deep);
}
.ticket-chip.done::before{
  content:"✓";
  display:flex;align-items:center;justify-content:center;
  border-color:var(--gold-deep);background:var(--gold-deep);
  color:var(--ivory);font-size:9px;line-height:1;font-weight:700;
  text-decoration:none;
}
html.theme-dark .ticket-chip,
:root[data-theme="dark"] .ticket-chip{box-shadow:0 6px 18px rgba(0,0,0,.35)}

/* ---------------- the milestone stack and the ledger ---------------- */
/* Three slips at the top right corner were debris at the margin: nothing in
   the beat stood near them and nothing in the beat explained them. They belong
   to the ledger, which is the line that counts them, so they stand on it —
   same right rail, same gold spine, milestone 2 then 3 then 4 piling down into
   `you: 4 lines · team: 4 milestones`. The offset is the ledger's own height
   (32.5px at its 11px/7px-padding) plus a 14px gap. */
.stack{
  position:absolute;right:clamp(12px,4%,40px);
  bottom:calc(clamp(14px,8%,54px) + 46.5px);
  z-index:6;pointer-events:none;
  display:flex;flex-direction:column;align-items:flex-end;gap:5px;
}
.stack-item{
  font-family:var(--mono);font-size:10px;letter-spacing:.08em;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);
  border-left:2px solid var(--gold-deep);border-radius:3px;
  padding:5px 9px;white-space:nowrap;
  opacity:0;transform:translateX(10px);
  transition:opacity .4s ease,transform .4s ease;
}
.stack-item.in{opacity:1;transform:none}

/* the proof line for "gets things done"; it survives into the night beat */
.ledger{
  position:absolute;right:clamp(12px,4%,40px);bottom:clamp(14px,8%,54px);
  margin:0;z-index:6;pointer-events:none;
  font-family:var(--mono);font-size:11px;letter-spacing:.04em;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);
  border-left:2px solid var(--gold-deep);border-radius:4px;   /* the slips' spine */
  padding:7px 11px;white-space:nowrap;
  opacity:0;visibility:hidden;transition:opacity .5s ease;
}
.ledger.on{opacity:1;visibility:visible}

/* the milestone: slides out of the ring toward the composer in beat 4,
   is read and steered in beat 5, then folds into the wall */
.paper-page{
  position:absolute;left:var(--x,50%);top:var(--y,48%);
  width:min(228px,46%);
  transform:translate(-50%,-50%) rotate(-5deg) scale(.86);
  z-index:6;opacity:0;visibility:hidden;pointer-events:none;
  background:#FFFCF8;color:#3D3125;
  border:1px solid rgba(90,70,40,.18);
  border-radius:2px 10px 2px 2px;
  padding:1.05rem 1.05rem 1.15rem;
  box-shadow:2px 3px 0 rgba(90,70,40,.08), 0 14px 32px rgba(80,60,30,.16);
  transition:opacity .45s ease,transform .5s cubic-bezier(.34,1.3,.64,1),
             left .8s cubic-bezier(.4,0,.2,1),top .8s cubic-bezier(.4,0,.2,1);
}
.paper-page.on{opacity:1;visibility:visible;transform:translate(-50%,-50%) rotate(-5deg) scale(1)}
.paper-page.folded{opacity:0;transform:translate(-50%,-50%) rotate(-26deg) scale(.32)}
.paper-fold{
  position:absolute;top:0;right:0;
  border-style:solid;border-width:0 18px 18px 0;
  border-color:#F2ECE1 #E6B574 #F2ECE1 #E6B574;
}
.paper-title{
  margin:0 1.1rem 0 0;
  font-family:var(--serif);font-size:1.05rem;font-weight:600;line-height:1.2;
  letter-spacing:-.01em;
}
/* scene copy */
.layer{
  position:absolute;inset:0;z-index:7;pointer-events:none;
  display:flex;flex-direction:column;justify-content:flex-end;
  padding:0 clamp(20px,4.5%,52px) clamp(76px,14%,116px);
  opacity:0;visibility:hidden;transition:opacity .4s ease;
}
.layer.on{opacity:1;visibility:visible}
.layer .say{
  font-size:clamp(16px,2.3vw,25px);line-height:1.34;margin:0;max-width:17em;
  font-weight:500;letter-spacing:-.01em;
}
.layer .say em{font-style:normal;color:var(--gold-ink)}

.layer--top{justify-content:flex-start;padding-top:clamp(20px,5%,44px)}

/* the three night questions, stacked above the stamp */
.night-qs{
  display:flex;flex-direction:column;align-items:center;gap:10px;
  margin:0;padding:0 8%;
}
.night-q{
  font-size:clamp(15px,1.7vw + .4rem,25px);line-height:1.18;font-weight:600;
  letter-spacing:-.01em;text-align:center;
  opacity:0;transform:translateY(10px);
  transition:opacity .55s ease,transform .55s ease;
}
.night-q.vis{opacity:1;transform:none}

/* composer */
.composer{
  position:absolute;left:50%;bottom:clamp(18px,7%,58px);
  transform:translateX(-50%) translateY(14px);
  z-index:6;display:flex;align-items:center;gap:11px;max-width:88%;
  background:var(--paper);border:1px solid var(--line);border-radius:999px;
  padding:13px 22px;box-shadow:0 10px 30px rgba(80,60,30,.12);
  opacity:0;transition:opacity .5s ease,transform .5s ease;
}
.composer.on{opacity:1;transform:translateX(-50%) translateY(0)}
.composer .dot{width:7px;height:7px;border-radius:50%;background:var(--gold-deep);flex:none}
.composer .txt{font-family:var(--mono);font-size:clamp(11px,1.5vw,14px);white-space:nowrap;color:var(--ink)}
.composer .caret{
  display:inline-block;width:1px;height:1.05em;background:var(--ink);
  vertical-align:-2px;margin-left:2px;animation:blink 1s steps(1) infinite;
}
@keyframes blink{50%{opacity:0}}

/* in-stage CTA */
.cta-wrap{
  position:absolute;inset:0;z-index:9;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:26px;
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .5s ease;
}
.cta-wrap.on{opacity:1;visibility:visible}
.cta-wrap.sealed{pointer-events:auto}
.cta-wrap::before{
  content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(660px,78%);aspect-ratio:2.2/1;border-radius:50%;
  background:radial-gradient(ellipse,rgba(35,33,44,.9) 32%,rgba(35,33,44,0) 70%);
  z-index:-1;pointer-events:none;
}
/* ---------------- the stamp ---------------- */
.seal-cta{
  display:inline-flex;align-items:center;justify-content:center;gap:.55rem;
  min-width:44px;min-height:44px;          /* hit target, measured unrotated */
  padding:.75rem 1.4rem;
  border:2.5px solid var(--seal);border-radius:6px;
  background:transparent;                   /* the stamp is an outline */
  color:inherit;
  font-family:var(--serif);font-size:1.05rem;
  text-decoration:none;
  transform:rotate(-6deg);
}
/* The waitlist pill, carried over from version C (kami's .btn-primary).
   Filled seal red by decision (2026-09-20); the "never fill" rule is
   retired. The stamp survives as the animation's closing beat inside the
   stage. */
.btn-primary{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-width:158px;min-height:44px;padding:13px 28px;
  background:var(--seal);color:var(--ivory);
  border:1.5px solid var(--seal);border-radius:999px;
  font-family:var(--serif);font-weight:500;font-size:15px;letter-spacing:.2px;
  text-decoration:none;cursor:pointer;
  transition:background .15s,border-color .15s,transform .15s;
}
@media (hover:hover){
  .btn-primary:hover{
    background:var(--seal-hover);border-color:var(--seal-hover);
    transform:translateY(-1px);
  }
}
.btn-primary:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.cta-wrap .seal-cta{opacity:0}
.cta-wrap.sealed .seal-cta{opacity:1;animation:stamp .55s cubic-bezier(.34,1.3,.64,1) both}
@keyframes stamp{
  0%{transform:rotate(-6deg) scale(2.2);opacity:0}
  60%{transform:rotate(-6deg) scale(.92);opacity:1}
  100%{transform:rotate(-6deg) scale(1);opacity:1}
}
.seal-cta:hover{border-color:var(--ink)}

/* ---------------- controls ---------------- */
.stage-controls{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin-top:14px;
}
.ctl,.chapters button{
  font-family:var(--mono);font-size:11px;letter-spacing:.04em;
  min-height:44px;padding:0 14px;
  border:1px solid var(--line);border-radius:4px;
  background:transparent;color:var(--ink);cursor:pointer;
}
.ctl:hover,.chapters button:hover{border-color:var(--gold-deep)}
.ctl[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.chapters{display:flex;flex-wrap:wrap;gap:6px;margin-left:auto}
.chapters button{color:var(--ink-soft);padding:0 11px}
.chapters button.now{background:var(--ink);border-color:var(--ink);color:var(--paper)}

/* ---------------- four words ---------------- */
.words{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  gap:26px 44px;
  max-width:1100px;margin:0 auto;
  padding:clamp(30px,5vw,54px) clamp(18px,5vw,56px);
}
.words div{max-width:26em}
.words b{
  display:block;font-family:var(--mono);font-size:11px;font-weight:400;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink);margin-bottom:6px;
}

/* ---------------- shared section chrome ---------------- */
.principles,.questions{
  max-width:1100px;margin:0 auto;
  padding:clamp(30px,5vw,56px) clamp(18px,5vw,56px);
  border-top:1px solid var(--line);
}
.section-label{
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--gold-ink);margin:0 0 clamp(20px,3vw,30px);
}

/* ---------------- principles ---------------- */
.principles ol{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(19rem,1fr));
  gap:clamp(24px,3.2vw,40px);
  counter-reset:principle;
}
.principles li{counter-increment:principle;max-width:32em}
.principles li::before{
  content:counter(principle);
  display:block;font-family:var(--mono);font-size:11px;
  color:var(--gold-ink);margin-bottom:8px;
}
.principles b{
  display:block;font-weight:600;font-size:clamp(1.05rem,1.1vw + .8rem,1.2rem);
  letter-spacing:-.01em;margin-bottom:6px;
}
.principles span{display:block;color:var(--ink)}

/* ---------------- questions ---------------- */
.questions details{border-bottom:1px solid var(--line)}
.questions details:first-of-type{border-top:1px solid var(--line)}
.questions summary{
  display:flex;align-items:center;gap:.7rem;
  min-height:44px;padding:14px 0;          /* hit target */
  font-size:clamp(1rem,.6vw + .9rem,1.1rem);font-weight:600;
  cursor:pointer;list-style:none;
}
.questions summary::-webkit-details-marker{display:none}
.questions summary::before{
  content:"+";flex:none;width:1rem;
  font-family:var(--mono);font-weight:400;color:var(--gold-ink);
}
.questions details[open] summary::before{content:"\2212"}   /* minus */
.questions details p{
  margin:0 0 18px;padding-left:1.7rem;max-width:44em;color:var(--ink);
}
.questions code{
  font-family:var(--mono);font-size:.88em;
  background:var(--code-bg);padding:1px 5px;border-radius:3px;
}

/* ---------------- closing ask ---------------- */
.ask{
  max-width:1100px;margin:0 auto;
  padding:clamp(30px,5vw,60px) clamp(18px,5vw,56px) clamp(40px,6vw,72px);
  border-top:1px solid var(--line);
}
.ask h2{
  font-size:clamp(1.6rem,3.4vw + .6rem,2.6rem);line-height:1.1;font-weight:600;
  letter-spacing:-.015em;margin:0 0 16px;
}
.ask p{margin:0 0 22px;max-width:34em}

/* ---------------- phone ---------------- */
/* At 375 the stage is 322.5px wide and one beat can have nine things on it at
   once: the caption, the pinned mission, four ghosts with their labels, three
   ticket chips, an Ask, the milestone paper, the ledger, the composer and the
   stamp. There is no arrangement of those inside a 3:4 box at this width that
   does not collide, so on a phone the stage becomes a tall column and a beat
   is read in horizontal bands, top to bottom (measured px at 375, where the
   stage is 322.5 x 645):

     pinned mission        20 .. 116    (left; the milestone slips sit right)
     the team, in one row 142 .. 220
     the beat's work      230 .. 508    (Asks, chips, the milestone paper)
     the caption          517 .. 560
     composer or ledger   579 .. 625

   The narrowest gap between any two of the audited groups, over all seven
   beats, is 18.9px, so this is not a hairline fit.

   The brief allows the phone stage to grow past 3:4 for exactly this. Seats
   are named in JS — stage[data-seats], .tickets[data-at], .paper-page[data-at]
   — and placed here, so no position is written imperatively inside a play()
   and enter() stays idempotent. Nothing below changes a colour or an opacity,
   so no contrast ratio moves. */
@media (max-width:640px){
  .stage{aspect-ratio:1/2}

  .mission{max-width:58%}
  /* Beat 1 is an empty field, so the egg sits in the band the team will
     later stand in rather than under "Quill leads." */
  .seed{top:36%}

  /* the team stands in one row under the mission: four 34px shells whose
     labels (up to ~47px) still clear the stage edges */
  .ghost{width:34px}
  .stage[data-seats="team"] #g0{left:15%;top:28%}
  .stage[data-seats="team"] #g1{left:38%;top:28%}
  .stage[data-seats="team"] #g2{left:62%;top:28%}
  .stage[data-seats="team"] #g3{left:85%;top:28%}
  /* the closing frame: the captain above the questions, two out at the rim
     beside the stamp, the coder below it */
  .stage[data-seats="wide"] #g0{left:50%;top:28%}
  .stage[data-seats="wide"] #g1{left:88%;top:58%}
  .stage[data-seats="wide"] #g2{left:50%;top:71%}
  .stage[data-seats="wide"] #g3{left:12%;top:58%}

  /* The walls follow the people. Left at their desktop seats they read as four
     loose circles scattered behind the work, so on a phone each member wall
     goes round its member and the team wall goes round the band where the work
     happens, with the row standing on its rim. `.faint` is only ever set for
     the `wide` ring, so the night beat still opens the wall out. */
  #ring{left:50%;top:53%;width:76%}
  #ring.faint{width:96%}
  #wall0{left:38%;top:26%;width:17%}
  #wall1{left:62%;top:26%;width:17%}
  #wall2{left:85%;top:26%;width:17%}

  /* the Asks: beat 2 stacks its accepted and declined pair in the work band;
     beats 3 and 4 hang theirs under the thing that is crossing */
  .askbox{padding:8px 11px 9px}
  .askbox-q{margin-bottom:6px}
  .askbox-a span{padding:3px 8px}
  #ask1{left:50%;top:46%}
  #ask2{left:50%;top:60%}
  #ask3{left:50%;top:64%}
  #ask4{left:50%;top:64%}

  /* the ticket stack travels down the work band rather than across it: three
     chips are 181px wide and there is nowhere sideways to go */
  .tickets[data-at="ash"]{left:50%;top:44.5%}
  .tickets[data-at="quill"]{left:50%;top:46%}
  .tickets[data-at="fen"]{left:50%;top:48%}

  /* wider and tighter, so the milestone's one line wraps twice instead of
     three times and the paper is 91px tall instead of 150 */
  .paper-page{width:78%;padding:.8rem .9rem .9rem}
  .paper-title{margin-right:.7rem}
  .paper-page[data-at="ring"]{left:50%;top:40%}
  .paper-page[data-at="composer"]{left:50%;top:48%}

  .layer .say{max-width:none}
  .layer{padding-bottom:84px}

  /* on a phone the bottom band is the ledger's alone, so the slips keep the
     top right corner W04 gave them; cancel the desktop bottom anchor. */
  .stack{top:3%;bottom:auto}
  .stack-item{font-size:9px;padding:4px 7px}
  .ledger{font-size:10px;bottom:20px}
  .composer{bottom:20px}

  /* tighten the closing frame so the questions and the stamp leave a band
     above for the captain and a band below for the coder */
  .cta-wrap{gap:18px}

  /* four chapters then three: two rows with room to spare, rather than two
     rows with 17px of slack that a wider text metric turns into three */
  .chapters button{padding:0 9px;font-size:10.5px}
}

/* ---------------- reduced motion ---------------- */
@media (prefers-reduced-motion: reduce){
  .mote,.ghost-float,.core,.composer .caret,.seed.on{animation:none !important}
  .egg{transition:none !important;transform:none}
  .ticket-chip,.mission-line,.stack-item,.night-q{transform:none}
  .nest.on path{animation:none;stroke-dashoffset:0}
  .ghost.on{animation:none;transform:translate(-50%,-50%) scale(1)}
  .cta-wrap.on .seal-cta{animation:none}
  .seal-cta,.paper-page{transform:none}
  .paper-page.on{transform:none}
  *,*::before,*::after{transition-duration:.01ms !important}
}
