/* nDirector Jr. — the design system.

   Four paradigms, one type scale, one set of tokens. A screen is in exactly
   one paradigm (body[data-paradigm]) and never mixes another's colours —
   tests/test_design_system.py pins that.

   MOTION lives in two places and nowhere else: the --m multiplier below and
   app/static/motion.js. Every duration in this file is calc(Nms * var(--m)),
   so the whole feel is one number. See docs/ART_CONTRACT.md before replacing
   the art or retiming the animation. */
/* ---------- tokens: the four paradigms (PLAN.md §3.6) ----------
   This mockup is single-theme by design: each stage paints its own
   paper explicitly, so it holds on any host ground. */
:root{
  --parchment:#F3EBDA; --parchment-deep:#E9DEC6; --graphite:#2B2A27;
  --pencil:#4A4642; --pencil-soft:#8C857A; --bronze:#8B7355;
  --drafting:#FCFBF8; --construction:#9AA3AB; --blueprint:#5B6B7A;
  --marker-warm:#D9A066; --marker-cool:#7A9CB5; --marker-gray:#B8B4AC;
  --ink:#0C0C0C; --white:#FAFAFA; --gray:#4A4A4A; --hair:#DCDCDC; --bg:#F4F4F2;
  --hand:'Caveat','Segoe Print','Bradley Hand',cursive;
  --sans:'Plus Jakarta Sans',system-ui,-apple-system,'Segoe UI',sans-serif;
  --m:1;                 /* motion multiplier: ?fast=1 → .12, reduced-motion → .2 */
  --drop:96px;           /* how far the whole stage sits below the top (Luc: about an inch) */
  --ground:var(--parchment); --text:var(--graphite); --muted:var(--pencil-soft);
  --line:var(--pencil); --accent:var(--bronze); --paper:#FBF6EA;
  color-scheme:light;
}
body[data-paradigm="drafting"]{--ground:#E4EEFB; --text:var(--graphite); --muted:var(--construction); --line:var(--blueprint); --accent:var(--blueprint); --paper:#FFFFFF}
body[data-paradigm="marker"]{--ground:#FFFFFF; --text:var(--graphite); --muted:#8F8A80; --line:var(--graphite); --accent:var(--marker-warm); --paper:#FFFDF8}
body[data-paradigm="pitch"]{--ground:#FFFFFF; --text:var(--ink); --muted:var(--gray); --line:var(--ink); --accent:var(--bronze); --paper:var(--white)}

*{box-sizing:border-box}
html,body{height:100%}
body{margin:0; background:var(--ground); color:var(--text); font-family:var(--sans); font-size:15px; line-height:1.45;
  -webkit-font-smoothing:antialiased; transition:background-color calc(600ms*var(--m))}
/* Paper texture, if the art pack supplies one. art.js sets --paper-texture and
   the has-texture class when art/manifest.json names a `texture`; with no file
   this rule never applies and the flat --ground colour stands, unchanged.
   It is a fixed overlay so it does not scroll with the walk, and it never
   prints (the pitch is its own paradigm and must stay clean). */
body.has-texture::before{content:""; position:fixed; inset:0; z-index:0; pointer-events:none;
  /* cover, not repeat: the sheet has painted corners, and tiling it prints a
     grid of identical blobs with visible seams */
  background-image:var(--paper-texture); background-size:cover;
  background-position:center; background-repeat:no-repeat;
  opacity:.55; mix-blend-mode:multiply}
/* The drafting stage is worked out on BLUEPRINT paper, not the cream sheet.
   Same overlay, different stock — and no multiply, the blue is the ground. */
body[data-paradigm="drafting"].has-texture::before{
  background-image:var(--blueprint-paper, none); mix-blend-mode:normal; opacity:.9}
/* Past the peel there is no paper at all — plain white. The last two stages
   are the finished work, and they should read as a gallery wall rather than
   as another sheet of stock. */
body[data-paradigm="marker"].has-texture::before,
body[data-paradigm="pitch"].has-texture::before{display:none}
@media print{body.has-texture::before{display:none}}
/* a tall screen gets the portrait sheet, when the pack supplies one */
@media (max-aspect-ratio: 3/4){
  body.has-texture::before{background-image:var(--paper-texture-portrait, var(--paper-texture))}
}

button{font:inherit; color:inherit; background:none; border:0; padding:0; cursor:pointer}
button:focus-visible,[contenteditable]:focus-visible,input:focus-visible{outline:2px solid var(--accent); outline-offset:3px}
input{font:inherit; color:inherit}

#stage{position:relative; height:100%; overflow:hidden; padding:0 16px}
.scene{position:absolute; inset:0; display:none; padding:0 16px 84px; opacity:0}
/* Everything sits --drop lower on the page (Luc: about an inch) — but the
   shift has to be applied per LAYOUT, not once on .scene, or it silently comes
   out wrong. Moving the scene's `top` shortens the box, so a CENTRED scene
   only moves half the distance (measured: a 96px top gave a 48px shift). So:
   a centred scene is TRANSLATED, which moves it exactly --drop and costs no
   height; a scrolling scene gets real padding, which it can afford; and the
   walk is left alone, because its ground line, the egg's feet and the sentence
   are anchored to the scene's BOTTOM on purpose. */
#s-idea, #s-final{transform:translateY(var(--drop))}
#s-review, #s-concept, #s-pitch{padding-top:var(--drop)}
.scene.on{display:flex; flex-direction:column; align-items:center; animation:fadein calc(500ms*var(--m)) ease-out forwards}
@keyframes fadein{to{opacity:1}}
.scene.leaving{animation:fadeout calc(400ms*var(--m)) ease-in forwards}
@keyframes fadeout{to{opacity:0}}

/* ---------- HUD ---------- */
#checklist{position:fixed; left:50%; bottom:calc(30px + env(safe-area-inset-bottom,0px)); transform:translateX(-50%); display:flex; gap:28px; list-style:none; margin:0; padding:0; white-space:nowrap;
  font-family:var(--hand); font-size:22px; color:var(--muted); opacity:0; pointer-events:none;
  transition:opacity calc(400ms*var(--m))}
#checklist.shown{opacity:1}
#checklist li{display:flex; gap:10px; align-items:center; line-height:1.5}
#checklist li .mk{display:inline-block; width:18px; text-align:center; line-height:1}
#checklist li.done{color:var(--text)}
body[data-paradigm="pitch"] #checklist, body[data-paradigm="drafting"] #checklist, body[data-paradigm="marker"] #checklist{font-family:var(--sans); font-size:13px; letter-spacing:.06em; text-transform:uppercase}
@media (max-width:640px){
  #checklist{gap:14px; font-size:17px; bottom:calc(22px + env(safe-area-inset-bottom,0px))}
  #checklist li{gap:5px}
  #checklist li .lbl{font-size:15px}
}

/* ---------- shared hand-drawn bits ---------- */
.hand{font-family:var(--hand)}
.eyebrow{font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); font-weight:600}
.btn{display:inline-flex; align-items:center; gap:8px; padding:11px 18px; border:1.5px solid var(--line); border-radius:3px;
  font-weight:600; font-size:14px; background:var(--paper); transition:transform calc(150ms*var(--m)), background calc(150ms*var(--m))}
.btn:hover{transform:translateY(-1px)}
.btn.primary{background:var(--line); color:var(--paper); border-color:var(--line)}
.btn.hand{font-family:var(--hand); font-size:22px; font-weight:600; border-radius:40% 60% 45% 55%/55% 45% 55% 45%; padding:8px 22px}
.btn.quiet{border-color:transparent; color:var(--muted); font-weight:500}

/* ---------- Stage 1: Idea ---------- */
#s-idea{justify-content:center; gap:26px}
/* The headline and the field are the two halves of one invitation, and they
   were reading as one block. Give the line room to be answered (Luc) — on the
   field rather than the scene's gap, which would widen egg-to-headline too. */
#s-idea .inputline{margin-top:26px}
.egg-wrap{position:relative; width:150px; height:190px}
/* When the pack supplies frames the box takes the DRAWING's shape instead —
   height comes from the first frame, which is left in flow (below), so no
   aspect is baked into this file and a replacement plate needs no code change.
   The two plates this host shows do not share proportions: the idle egg is a
   single upright drawing, the thinking plate is a wide sheet carrying the
   bubble, so only the WIDTH is stated per plate. */
.egg-wrap.framed{width:min(560px, 86vw); height:auto}
.egg-wrap.framed.plate-still{width:min(270px, 52vw)}
.egg-wrap.framed .frame:first-child{position:relative}
.egg-wrap.framed .frame:first-child > svg,
.egg-wrap.framed .frame:first-child > img{height:auto}
.egg{width:150px; height:190px; overflow:visible}
.egg .outline{fill:var(--paper); stroke:var(--line); stroke-width:2; stroke-linecap:round}
.egg .ghost{fill:none; stroke:var(--line); stroke-width:1; opacity:.35; stroke-dasharray:3 4}
.egg .crack{fill:none; stroke:var(--line); stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round; opacity:0; stroke-dasharray:80; stroke-dashoffset:80}
.egg.cracked .crack{opacity:1; animation:crackon calc(500ms*var(--m)) ease-out forwards}
@keyframes crackon{to{stroke-dashoffset:0}}
#egg1{cursor:default}
.egg .legs{opacity:0; transform-origin:60px 135px; transition:opacity calc(900ms*var(--m))}
.egg.has-legs .legs{opacity:1}
.egg .leg{stroke:var(--line); stroke-width:2.2; fill:none; stroke-linecap:round; transform-box:fill-box; transform-origin:50% 0}
.egg.pulse{animation:pulse calc(300ms*var(--m)) ease-out}
@keyframes pulse{0%{transform:scale(1)}40%{transform:scale(1.06) rotate(-1.5deg)}100%{transform:scale(1)}}
.egg.shake{animation:shake calc(900ms*var(--m)) ease-in-out}
/* The egg shakes while the model decides (Luc) — back and forth, a little,
   from the press of enter until "what else?" lands. Pure rotation: a drift up
   the page reads as floating rather than as effort. */
.egg.thinking,
.egg-wrap.thinking{animation:think calc(620ms*var(--m)) ease-in-out infinite}
@keyframes think{0%,100%{transform:rotate(0)}25%{transform:rotate(-2.6deg)}75%{transform:rotate(2.6deg)}}
.hint.think{letter-spacing:.3em}
@keyframes shake{0%,100%{transform:rotate(0)}15%{transform:rotate(-7deg)}30%{transform:rotate(6deg)}45%{transform:rotate(-5deg)}60%{transform:rotate(4deg)}75%{transform:rotate(-2deg)}}
.egg.walking .leg.l{animation:stepl calc(var(--stride,520ms)*var(--m)) ease-in-out infinite}
.egg.walking .leg.r{animation:stepr calc(var(--stride,520ms)*var(--m)) ease-in-out infinite}
@keyframes stepl{0%,100%{transform:rotate(-16deg)}50%{transform:rotate(16deg)}}
@keyframes stepr{0%,100%{transform:rotate(16deg)}50%{transform:rotate(-16deg)}}
.egg.walking{animation:bob calc(var(--stride,520ms)*var(--m)) ease-in-out infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}

.headline{font-family:var(--hand); font-size:clamp(28px,4.6vw,40px); font-weight:600; text-align:center; text-wrap:balance; margin:0; color:var(--text)}
.hint{font-family:var(--hand); font-size:22px; color:var(--muted); min-height:30px; text-align:center; opacity:0; transition:opacity calc(400ms*var(--m))}
.hint.shown{opacity:1}
.inputline{position:relative; display:flex; align-items:center; gap:12px; width:min(560px,100%); transition:opacity calc(250ms*var(--m))}
/* The (+) reserves its 38px even while hidden, so the field does not jump when
   it appears — which left the underline 25px off-centre under a centred
   headline. Balance it with the same space on the left. Desktop only: on a
   phone the field needs every pixel more than the composition does. */
@media (min-width:641px){ .inputline{padding-left:50px} }
.inputline.gone{opacity:0; pointer-events:none}
.inputline input{flex:1; background:transparent; border:0; border-bottom:1.5px solid var(--line); padding:8px 4px; font-family:var(--hand);
  font-size:26px; font-weight:500; color:var(--text)}
.inputline input::placeholder{color:var(--muted); opacity:.55}
/* The underline as a DRAWING when the pack has one: the border is dropped and
   the plate is painted along the bottom instead. `has-rule` is set by the art
   loader only once the file has actually arrived, so a missing or broken
   rule.png leaves the drawn border alone rather than leaving no line at all. */
body.has-rule .inputline input{border-bottom-color:transparent;
  background-image:var(--rule-art); background-repeat:no-repeat;
  background-position:center bottom; background-size:100% 10px; padding-bottom:14px}
body.has-rule .inputline input:focus,
body.has-rule .inputline input:focus-visible{outline:none;
  border-bottom-color:transparent; filter:contrast(1.35)}
/* No box around the field, ever (Luc) — a rectangle over a hand-drawn line is
   a form control arriving in the middle of a drawing. The underline IS the
   focus surface, so focus darkens it instead. Colour only: a thicker border
   would shift the field by half a pixel every time it is tabbed into. */
.inputline input:focus, .inputline input:focus-visible{outline:none;
  border-bottom-color:var(--graphite)}
.plus{width:38px; height:38px; display:grid; place-items:center; opacity:0; transform:scale(.6) rotate(-20deg); pointer-events:none;
  transition:opacity calc(250ms*var(--m)), transform calc(250ms*var(--m))}
.plus.shown{opacity:1; transform:none; pointer-events:auto}
/* The (+) is a DRAWING now, and a raster drawing carries its own natural size
   and ignores the button box — size it explicitly, as every art host must. */
.plus svg{width:34px; height:34px; overflow:visible}
.plus img{width:34px; height:34px; object-fit:contain; display:block}
.plus path{fill:none; stroke:var(--line); stroke-width:2; stroke-linecap:round}
/* Open used to tint the ring, which a drawing cannot do. Turning the plus into
   an × says "close" without needing to recolour anything. */
.plus.open path.ring{stroke:var(--accent)}
.plus.shown.open{transform:rotate(45deg)}
.rich{position:absolute; right:0; top:52px; background:var(--paper); border:1.5px solid var(--line); border-radius:6px; padding:8px; display:none;
  flex-direction:column; gap:2px; min-width:200px; box-shadow:0 12px 30px -18px rgba(43,42,39,.5); z-index:5}
.rich.shown{display:flex}
.rich button{display:flex; align-items:center; gap:10px; padding:8px 10px; border-radius:4px; font-size:14px; text-align:left}
.rich button:hover{background:var(--parchment-deep)}
.rich button span.i{width:18px; text-align:center; color:var(--muted)}
.rich button.soon{opacity:.45; cursor:default}
.rich button.soon em{margin-left:auto; font-size:10px; letter-spacing:.1em; text-transform:uppercase; font-style:normal; color:var(--muted)}
.thought-fly{position:fixed; font-family:var(--hand); font-size:24px; color:var(--text);
  pointer-events:none; white-space:nowrap; z-index:4; will-change:transform,opacity}
.said{pointer-events:none; position:fixed; left:50%; top:22%; transform:translate(-50%,0); font-family:var(--hand); font-size:clamp(26px,4vw,38px); font-weight:600;
  color:var(--text); text-align:center; opacity:0; z-index:6; padding:0 16px; width:max-content; max-width:calc(100vw - 32px); text-wrap:balance}
.said.shown{animation:card calc(2800ms*var(--m)) ease-out forwards}

/* ---------- waiting ----------
   The product's own answer to a spinner: a line saying what is being drawn,
   over a pencil rule with a graphite stroke travelling along it. INDETERMINATE
   on purpose — we do not know how long a model takes, and a bar that pretends
   to is a lie the person can see through. It never appears unless the work
   outlives MOTION.waitGrace, so pre-built work shows nothing at all. */
.wait{pointer-events:none; position:fixed; left:50%; bottom:112px;
  transform:translate(-50%,6px); display:flex; flex-direction:column;
  align-items:center; gap:10px; opacity:0; z-index:6; width:min(420px,calc(100vw - 48px));
  transition:opacity calc(300ms*var(--m)) ease, transform calc(300ms*var(--m)) ease}
.wait.shown{opacity:1; transform:translate(-50%,0)}
.wait-line{font-family:var(--hand); font-size:22px; color:var(--muted); text-align:center}
.wait-rule{position:relative; width:100%; height:2px; background:var(--line);
  opacity:.28; overflow:hidden; border-radius:2px}
.wait-rule > i{position:absolute; inset:0 auto 0 0; width:34%; background:var(--text);
  border-radius:2px; animation:waitrun calc(1700ms*var(--m)) ease-in-out infinite}
@keyframes waitrun{0%{transform:translateX(-110%)}100%{transform:translateX(330%)}}
body[data-paradigm="drafting"] .wait-line,
body[data-paradigm="marker"] .wait-line,
body[data-paradigm="pitch"] .wait-line{font-family:var(--sans); font-size:14px;
  letter-spacing:.06em; text-transform:uppercase}
@keyframes card{0%{opacity:0; transform:translate(-50%,10px)}12%{opacity:1; transform:translate(-50%,0)}85%{opacity:1}100%{opacity:0; transform:translate(-50%,-8px)}}
body[data-paradigm="drafting"] .said, body[data-paradigm="marker"] .said{font-family:var(--sans); font-size:clamp(20px,3vw,28px); font-weight:700}

/* Frame animation. Every frame of a sequence is rendered and stacked; only
   .on is visible. Swapping markup twice a second instead would re-decode the
   image each tick and flicker through the first cycle. */
.framed{position:relative}
/* the incoming plate of a cross-fade, stacked over the outgoing one */
.art-swap{position:absolute; inset:0; opacity:0}
.art-swap.in{opacity:1}
.egg-wrap.framed .art-swap > .frame{position:absolute}
.framed .frame{position:absolute; inset:0; opacity:0}
.framed .frame.on{opacity:1}
.framed .frame > svg, .framed .frame > img{display:block; width:100%; height:100%; object-fit:contain}

.ortho{margin:14px auto 0; max-width:min(760px, 92vw); text-align:center}
.ortho[hidden]{display:none}
.ortho-plate img{display:block; width:100%; height:auto; border:1px solid var(--rule,#DDD2BE)}
.ortho figcaption{margin-top:5px; font-family:var(--mono); font-size:11px;
  letter-spacing:.1em; text-transform:uppercase; color:var(--muted)}

/* ---------- The paper turn between paradigms ---------- */
/* The outgoing surface stays on screen as a real sheet and is removed
   physically, so a paradigm change reads as paper rather than a crossfade.
   Both moves are one element; only the animation differs. */
.turn{position:fixed; inset:0; z-index:240; pointer-events:none; perspective:1900px}
.turn[hidden]{display:none}
.turn-sheet{position:absolute; inset:0; background-color:var(--turn-ground,var(--parchment));
  background-image:var(--turn-paper,none); background-size:cover; background-position:center;
  transform-origin:left center; will-change:transform, clip-path}
.turn-shadow{position:absolute; inset:0; opacity:0; background:linear-gradient(90deg,
  rgba(43,42,39,.34), rgba(43,42,39,0) 45%)}

/* TURN: the parchment lifts at its right edge and swings over, like a page. */
.turn.flip .turn-sheet{animation:pageflip calc(var(--turn-ms,1150ms)*var(--m)) cubic-bezier(.42,0,.58,1) forwards}
.turn.flip .turn-shadow{animation:flipshade calc(var(--turn-ms,1150ms)*var(--m)) ease-out forwards}
/* Two stops only. An intermediate keyframe — even one that sets nothing but
   brightness — restarts the timing function for each segment, so the easing
   no longer spans the animation and the page swings most of its arc in the
   first third. */
@keyframes pageflip{
  0%  {transform:rotateY(0deg);    filter:brightness(1)}
  100%{transform:rotateY(-174deg); filter:brightness(.84)}
}
@keyframes flipshade{0%{opacity:0} 40%{opacity:1} 100%{opacity:0}}

/* PEEL: the blueprint is pulled off toward the upper right. The cut edge is a
   diagonal, so the top-right clears first and the bottom-left last. The two
   layers share the keyframes; the shadow lags, which leaves a soft dark band
   sitting on the newly revealed ground just ahead of the cut. */
.turn.peel .turn-sheet{animation:peelaway calc(var(--turn-ms,1250ms)*var(--m)) cubic-bezier(.38,0,.5,1) forwards}
.turn.peel .turn-shadow{opacity:1; background:linear-gradient(226deg,
  rgba(43,42,39,.22), rgba(43,42,39,0) 22%);
  animation:peelaway calc(var(--turn-ms,1250ms)*var(--m)) cubic-bezier(.38,0,.5,1) forwards;
  animation-delay:calc(var(--turn-ms,1250ms)*var(--m)*0.06)}
@keyframes peelaway{
  0%  {clip-path:polygon(0% 0%, 170% 0%, 110% 100%, 0% 100%)}
  100%{clip-path:polygon(0% 0%, 0% 0%, -62% 100%, 0% 100%)}
}
/* ---------- Stage 2: the walk ---------- */
#s-walk{justify-content:flex-end; padding-bottom:0}
.sky{position:absolute; left:0; right:0; top:0; bottom:0; overflow:hidden; z-index:0; will-change:transform}
.world{position:absolute; left:0; bottom:132px; height:340px; width:0; will-change:transform}
/* treadmill: the egg walks in place, the ground and everything on it come toward it */
.ground{position:absolute; left:0; right:0; bottom:176px; height:2px; background:var(--line); opacity:.6}
.ground::after{content:""; position:absolute; left:0; right:0; top:7px; height:2px; opacity:.35;
  background:repeating-linear-gradient(90deg, var(--line) 0 16px, transparent 16px 52px); background-position-x:var(--gx,0px)}
.ground::before{content:""; position:absolute; left:0; right:0; top:14px; height:6px; opacity:.28;
  background:radial-gradient(3px 2px at 6px 3px, var(--line) 60%, transparent 62%) 0 0/97px 6px repeat-x,
             radial-gradient(2px 2px at 40px 4px, var(--line) 60%, transparent 62%) 0 0/173px 6px repeat-x;
  background-position-x:var(--gx2,0px), var(--gx3,0px)}
.horizon{position:absolute; left:0; right:0; bottom:186px; height:96px; opacity:.5; pointer-events:none;
  background-image:var(--horizon-art); background-size:auto 96px; background-repeat:repeat-x;
  background-position-x:var(--gx4,0px)}
.walker{position:absolute; bottom:145px; left:50%; width:290px; height:249px; transform:translateX(-50%)}
.guidepost{position:absolute; bottom:2px; width:170px; transform:translateX(-50%); opacity:0; transform-origin:50% 100%; text-align:center}
.signart{width:100%}
.signart img, .signart svg{display:block; width:100%; height:auto}
.signsaid{margin-top:2px; font-family:var(--hand); font-size:14px; line-height:1.15; color:var(--muted); max-width:150px; margin-inline:auto}
.guidepost.shown{animation:postin calc(300ms*var(--m)) ease-out forwards}
@keyframes postin{to{opacity:1}}

/* The foreground: everything here paints IN FRONT of the walking egg, and
   scrolls with the world. The barn lives here — that is the whole trick. */
.fg{position:absolute; left:0; bottom:132px; height:340px; width:0; z-index:2; will-change:transform; pointer-events:none}
.barn{position:absolute; bottom:2px; width:471px; height:430px; transform:translateX(-50%)}
.barn svg{width:100%; height:100%; overflow:visible}
/* body and roof are FILLED with the paper, so the egg is hidden behind them */
.barn path{stroke:var(--line); stroke-width:2.5; fill:var(--paper); stroke-linecap:round; stroke-linejoin:round}
/* the window is a hole: no fill, so the egg behind shows through it */
.barn .win{stroke:var(--line); stroke-width:2.5; fill:none}
.barn .mullion, .barn .boards{stroke:var(--line); fill:none; stroke-linecap:round}
.barn .mullion{stroke-width:1.6}
.barn .boards{stroke-width:1.2; opacity:.45}
.sentence{z-index:3; position:absolute; left:50%; top:auto; bottom:452px; transform:translateX(-50%); width:min(900px,calc(100vw - 32px)); text-align:left; display:flex; align-items:center; justify-content:center; gap:.35em; padding-top:calc(var(--row) * 2.4);
  font-family:var(--hand); font-size:clamp(26px,4.2vw,40px); font-weight:500; line-height:1.3; opacity:0; transition:opacity calc(400ms*var(--m)); text-wrap:balance}
.sentence.shown{opacity:1}
/* the blank is a wheel: the current choice on the line, faded neighbours above and below,
   two more partially visible beyond. No popup. */
.sentence{--row:1.12em}
.picker{position:relative; display:inline-grid; align-items:center; justify-items:start; min-width:0; vertical-align:middle;
  padding:calc(var(--row) * 2.5) 4px; margin:calc(var(--row) * -2.5) 0;
  text-align:left; line-height:1.1; white-space:nowrap;
  -webkit-mask-image:linear-gradient(transparent 0, rgba(0,0,0,.28) 16%, #000 40%, #000 60%, rgba(0,0,0,.28) 84%, transparent 100%);
  mask-image:linear-gradient(transparent 0, rgba(0,0,0,.28) 16%, #000 40%, #000 60%, rgba(0,0,0,.28) 84%, transparent 100%);
  touch-action:none; user-select:none}
.picker .opt{grid-area:1/1; padding:0 4px; color:var(--pencil-soft); cursor:pointer;
  transform:translateY(calc(var(--o) * var(--row))); opacity:.55;
  transition:transform calc(250ms*var(--m)) cubic-bezier(.2,.7,.3,1), opacity calc(250ms*var(--m)), color calc(250ms*var(--m))}
.picker .opt.cur{color:var(--text); opacity:1; cursor:text; border-bottom:2px solid var(--line); min-width:120px; user-select:text}
.picker .opt.cur:empty::before{content:attr(data-ph); color:var(--pencil-soft)}
.picker .opt.cur[contenteditable="true"]{outline:none; border-bottom-color:var(--accent)}
.picker.typing .opt:not(.cur){opacity:0; pointer-events:none}
.picker .opt:not(.cur):hover{color:var(--pencil); opacity:.85}
.picker.locked .opt:not(.cur){opacity:0}
.picker.locked .opt.cur{border-bottom-color:var(--accent)}
.picker.locked{-webkit-mask-image:none; mask-image:none}
.sentence .lead{white-space:nowrap; flex:0 0 auto}
.blankwrap{display:flex; align-items:center; gap:6px; min-width:0; flex:0 1 auto}
.confirm{position:relative; z-index:2; display:inline-grid; place-items:center; width:1.15em; height:1.15em; vertical-align:middle; margin-left:6px; opacity:0; transform:scale(.6);
  transition:opacity calc(250ms*var(--m)), transform calc(250ms*var(--m))}
.confirm.shown{opacity:1; transform:none}
.confirm svg{width:100%; height:100%; overflow:visible}
.confirm path{fill:none; stroke:var(--line); stroke-width:2; stroke-linecap:round; stroke-linejoin:round}
.confirm:hover path.ring, .confirm:focus-visible path.ring{stroke:var(--accent)}
.confirm.done path{stroke:var(--accent)}
.blank-hint{position:absolute; left:50%; transform:translateX(-50%); bottom:0; font-size:14px; font-family:var(--sans); letter-spacing:.06em; text-transform:uppercase; color:var(--muted); white-space:nowrap}
.sentence{padding-bottom:calc(var(--row) * 3.6)}
.blank-hint{left:0; transform:none; width:100%; text-align:center}
/* the sentence is the egg's thought: an open, wavy bubble line and two little bubbles trailing to the egg */
.thought{position:absolute; left:50%; transform:translateX(-50%); bottom:396px; height:100px; z-index:2; pointer-events:none; overflow:visible}
.thought path, .thought circle{fill:none; stroke:var(--line); stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round; opacity:.75}
.thought .ghost{stroke-width:1; opacity:.28; stroke-dasharray:3 4}
/* A short screen does not have an inch to give — take it back rather than
   push the composition off the bottom. */
@media (max-height:760px){:root{--drop:48px}}
@media (max-height:640px){:root{--drop:16px}}
@media (max-height:720px){.sentence{font-size:clamp(22px,3.2vw,28px); --row:1.02em; bottom:436px}}
@media (hover:none){.hint-kbd{display:none}}
@media (hover:hover){.hint-touch{display:none}}
@media (max-width:640px){
  .sentence{--row:2.5em; font-size:22px; gap:.3em}
  .picker{white-space:normal; font-size:.95em}
  .picker .opt{white-space:normal; line-height:1.05}
  .blank-hint{white-space:normal; width:100%; left:0; transform:none; font-size:11px; line-height:1.3}
  .sentence{padding-bottom:calc(var(--row) * 2.6); bottom:440px}
}

/* ---------- Stage 3: review (drafting) ---------- */
#s-review{justify-content:flex-start; gap:18px; overflow:auto}
#s-review > *{flex-shrink:0}
.desktop{width:min(760px,100%); background:var(--paper); border:1px solid var(--construction); padding:28px clamp(18px,4vw,40px) 26px; position:relative;
  box-shadow:0 30px 60px -40px rgba(43,42,39,.4)}
.desktop::before{content:""; position:absolute; inset:0; background-image:linear-gradient(var(--construction) 1px, transparent 1px);
  background-size:100% 28px; opacity:.16; pointer-events:none}
.desktop h2{font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); margin:0 0 14px; font-weight:600}
.opp-row{display:grid; grid-template-columns:150px 1fr; gap:14px; padding:7px 0; border-bottom:1px solid var(--hair); align-items:baseline}
.opp-row .k{font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--blueprint); font-weight:700}
.opp-row .v{font-size:16px; line-height:1.5; padding:2px 6px; margin:-2px -6px; border-radius:3px; min-height:1.4em}
.opp-row .v:hover{background:rgba(91,107,122,.08)}
.opp-row .v:focus{background:#fff; outline:1.5px solid var(--blueprint)}
.para{margin:16px 0 4px; font-size:17px; line-height:1.55; padding:8px 10px; border-left:3px solid var(--blueprint); background:rgba(91,107,122,.05)}
.para:focus{outline:1.5px solid var(--blueprint); background:#fff}
.walk-strip{display:flex; gap:12px; flex-wrap:wrap; justify-content:center; width:min(760px,100%)}
.walk-strip .gp{background:var(--paper); border:1px solid var(--construction); padding:6px 8px 4px; width:104px; font-family:var(--hand); font-size:15px; line-height:1.1; color:var(--text); transform:rotate(-1.5deg)}
.walk-strip .gp:nth-child(even){transform:rotate(1.2deg)}
.walk-strip .gp svg{display:block; width:100%; height:36px; margin-bottom:3px}
.walk-strip .gp svg g{stroke:var(--blueprint)}
.tiny-egg{position:absolute; right:-18px; bottom:-14px; width:44px; height:56px; opacity:.85; overflow:hidden}
/* raster art has a natural size and will happily ignore its container */
.tiny-egg img, .tiny-egg svg{display:block; width:100%; height:100%; object-fit:contain}
.tiny-egg .outline{fill:var(--paper); stroke:var(--line); stroke-width:2}
.editnote{font-size:12px; color:var(--muted); text-align:center}
@media (max-width:640px){.opp-row{grid-template-columns:1fr; gap:2px}}

/* ---------- Stage 4: concept sheets (drafting) ---------- */
#s-concept{justify-content:flex-start; overflow:auto; gap:14px}
.concept-head{width:min(1060px,100%); display:flex; justify-content:space-between; align-items:baseline; gap:12px; flex-wrap:wrap}
.concept-head h2{margin:0; font-size:18px; font-weight:700}
.sheets{width:min(1060px,100%); display:flex; flex-direction:column; gap:18px}
.sheet{background:#fff; border:1px solid var(--construction); padding:16px; position:relative; opacity:0; transform:translateY(10px);
  animation:sheetin calc(400ms*var(--m)) ease-out forwards; box-shadow:0 24px 50px -40px rgba(43,42,39,.5)}
@keyframes sheetin{to{opacity:1; transform:none}}
.sheet::before{content:""; position:absolute; inset:0; pointer-events:none; opacity:.35;
  background-image:linear-gradient(90deg,rgba(154,163,171,.35) 1px,transparent 1px),linear-gradient(rgba(154,163,171,.35) 1px,transparent 1px); background-size:40px 40px}
.sheet .tag{position:relative; font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); font-weight:600; margin-bottom:10px; display:flex; gap:10px; align-items:baseline}
.sheet .tag b{color:var(--blueprint); font-weight:700}
.dirs{position:relative; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px}
@media (max-width:760px){.dirs{grid-template-columns:1fr}}
.dir{cursor:pointer; border:1px dashed var(--construction); padding:10px; background:rgba(255,255,255,.7); display:flex; flex-direction:column; gap:8px; position:relative; transition:box-shadow calc(150ms*var(--m))}
.dir.cmp{box-shadow:0 0 0 2px var(--blueprint) inset}
.dir.selected{box-shadow:0 0 0 2px var(--graphite) inset}
.dir .sketch{width:100%; aspect-ratio:4/3; background:#fff; border:1px solid var(--construction);
  display:grid; place-items:center; overflow:hidden}
.dir .sketch img{width:100%; height:100%; object-fit:cover; display:block}
.dir .sketching{display:flex; gap:8px; align-items:center; font-size:12px; color:var(--muted);
  letter-spacing:.04em; text-align:center; padding:8px}
.dir .sketching i{width:10px; height:10px; border:2px solid var(--muted); border-right-color:transparent;
  border-radius:50%; animation:spin .8s linear infinite; flex:0 0 auto}
.dir h3{margin:0; font-size:15px; font-weight:700}
.dir p{margin:0; font-size:13px; color:var(--gray); line-height:1.45}
.dir ul{margin:0; padding-left:16px; font-size:12.5px; color:var(--gray); display:none}
.dir.open ul{display:block}
.dir .acts{display:flex; gap:6px; flex-wrap:wrap; margin-top:auto}
.dir .acts button{font-size:12px; font-weight:600; padding:6px 9px; border:1px solid var(--construction); border-radius:3px; background:#fff}
.dir .acts button.sel{background:var(--graphite); color:#fff; border-color:var(--graphite)}
.dir .acts button.on{background:var(--blueprint); color:#fff; border-color:var(--blueprint)}
.dir .open-hint{font-size:11px; color:var(--muted); letter-spacing:.06em; text-transform:uppercase}
.dir.open .open-hint{display:none}
.games{width:min(1060px,100%); display:flex; flex-wrap:wrap; gap:8px; align-items:center}
.games .eyebrow{margin-right:6px}
.game{font-size:13px; font-weight:600; padding:8px 12px; border:1.5px solid var(--blueprint); color:var(--blueprint); border-radius:3px; background:#fff}
.game:hover{background:var(--blueprint); color:#fff}
.game[disabled]{opacity:.4; cursor:not-allowed}
.game[disabled]:hover{background:#fff; color:var(--blueprint)}
.game.extra{display:none}
.games.expanded .game.extra{display:inline-flex}
.games .more{font-size:13px; font-weight:600; color:var(--muted); padding:8px 6px; text-decoration:underline dotted}
.compare{width:min(1060px,100%); display:none; grid-template-columns:1fr 1fr; gap:14px; background:#fff; border:1px solid var(--construction); padding:14px}
.compare.shown{display:grid}
@media (max-width:760px){.compare{grid-template-columns:1fr}}
.compare h4{margin:0 0 6px; font-size:14px}
.compare ul{margin:6px 0 0; padding-left:16px; font-size:12.5px; color:var(--gray)}
.compare img{width:100%; aspect-ratio:4/3; object-fit:cover; display:block}
.spinner{font-size:13px; color:var(--muted); display:none; align-items:center; gap:8px}
.spinner.shown{display:flex}
.spinner i{width:10px; height:10px; border:2px solid var(--muted); border-right-color:transparent; border-radius:50%; animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- Stage 4b: final marker render ---------- */
#s-final{justify-content:center; gap:20px}
.render{position:relative; width:min(720px,100%); aspect-ratio:16/10; background:var(--paper); border:1px solid var(--marker-gray); padding:18px; opacity:0; transform:scale(.97);
  animation:renderin calc(800ms*var(--m)) ease-out forwards; box-shadow:0 40px 80px -50px rgba(43,42,39,.55)}
@keyframes renderin{to{opacity:1; transform:none}}
.render .layer{position:absolute; inset:18px; transition:opacity calc(900ms*var(--m)) ease-in-out}
.render .layer img{width:100%; height:100%; object-fit:contain; display:block}
.render .layer.marker{opacity:0}
.render.resolved .layer.marker{opacity:1}
.render.resolved .layer.pencil{opacity:0}
.render-cap i{width:10px; height:10px; border:2px solid var(--muted);
  border-right-color:transparent; border-radius:50%; animation:spin .8s linear infinite}
.render-cap{position:absolute; left:18px; bottom:10px; font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); display:flex; gap:8px; align-items:center}
.render.resolved .render-cap{display:none}
.render-meta{width:min(720px,100%); display:grid; grid-template-columns:1fr auto; gap:14px; align-items:end}
.render-meta h2{margin:0; font-size:26px; font-weight:800; letter-spacing:-.02em}
.render-meta p{margin:4px 0 0; color:var(--muted); font-size:15px; max-width:52ch}
@media (max-width:640px){.render-meta{grid-template-columns:1fr}}

/* ---------- Stage 5: pitch ---------- */
#s-pitch{justify-content:flex-start; overflow:auto; gap:16px}
.pitch-head{width:min(1100px,100%); display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap}
.pitch-head h2{margin:0; font-size:18px; font-weight:700}
.assembling{width:min(520px,100%); display:flex; flex-direction:column; gap:10px; padding:20px 0; font-size:14px; color:var(--muted)}
.assembling div{display:flex; gap:10px; align-items:center; opacity:0; transform:translateY(4px); transition:opacity calc(300ms*var(--m)), transform calc(300ms*var(--m))}
.assembling div.on{opacity:1; transform:none; color:var(--text)}
.assembling div::before{content:"○"; color:var(--muted); width:16px}
.assembling div.on::before{content:"✓"; color:var(--bronze)}
.strip{width:min(1100px,100%); display:grid; grid-template-columns:repeat(auto-fill,minmax(232px,1fr)); gap:14px}
.thumb{position:relative; width:100%; aspect-ratio:11/8.5; overflow:hidden; background:#fff; border:1px solid var(--hair); box-shadow:0 10px 24px -18px rgba(0,0,0,.45); cursor:zoom-in}
.thumb .page{transform-origin:0 0; position:absolute; left:0; top:0}
.thumb .n{position:absolute; left:6px; bottom:4px; font-size:10px; letter-spacing:.1em; text-transform:uppercase; color:var(--gray); background:rgba(255,255,255,.85); padding:2px 6px}
.lightbox{position:fixed; inset:0; background:rgba(12,12,12,.72); display:none; place-items:center; z-index:20; padding:16px}
.lightbox.shown{display:grid}
body.lb-open .strip, body.lb-open .strip-hint, body.lb-open .pitch-done, body.lb-open .assembling{visibility:hidden}
.lightbox .scroll{display:grid; place-items:center}
.lightbox .frame{position:relative; width:1056px; height:816px; transform-origin:center; background:#fff; box-shadow:0 40px 90px -30px rgba(0,0,0,.7)}
.lightbox .nav{position:absolute; top:50%; transform:translateY(-50%); color:#fff; font-size:40px; line-height:1; padding:12px 14px; opacity:.85}
.lightbox .nav.prev{left:6px} .lightbox .nav.next{right:6px}
.lightbox .pn{position:absolute; left:50%; bottom:calc(14px + env(safe-area-inset-bottom,0px)); transform:translateX(-50%); color:#fff; font-size:12px; letter-spacing:.14em; text-transform:uppercase; opacity:.8}
.strip-hint{width:min(1100px,100%); font-size:12px; color:var(--muted); letter-spacing:.06em; text-transform:uppercase}
.lightbox .close{position:absolute; right:16px; top:calc(16px + env(safe-area-inset-top,0px)); color:#fff; font-size:28px; line-height:1; padding:6px 10px}
.pitch-done{width:min(720px,100%); text-align:center; display:none; flex-direction:column; align-items:center; gap:14px; padding:20px 0}
.pitch-done.shown{display:flex}
.pitch-done h2{margin:0; font-size:28px; font-weight:800; letter-spacing:-.02em}
.pitch-done p{margin:0; color:var(--muted); max-width:56ch}

/* ----- the deterministic pitch page (1056×816 = letter landscape @96dpi) ----- */
.page{width:1056px; height:816px; background:#fff; color:var(--ink); font-family:var(--sans); position:relative; padding:56px 64px 48px; display:flex; flex-direction:column; overflow:hidden}
.page .foot{position:absolute; left:64px; right:64px; bottom:26px; display:flex; justify-content:space-between; font-size:10px; letter-spacing:.14em; text-transform:uppercase; color:var(--gray); border-top:1px solid var(--hair); padding-top:8px}
.page .eb{font-size:11px; letter-spacing:.16em; text-transform:uppercase; color:var(--gray); font-weight:600; margin-bottom:10px}
.page h1{margin:0; font-size:44px; font-weight:800; letter-spacing:-.03em; line-height:1.05}
.page h2{margin:0 0 18px; font-size:34px; font-weight:800; letter-spacing:-.03em; line-height:1.08}
.page p{margin:0; font-size:15px; line-height:1.55; color:#222}
.page .cols{display:grid; grid-template-columns:1fr 1fr; gap:36px; flex:1; min-height:0}
.page .cols3{display:grid; grid-template-columns:repeat(3,1fr); gap:24px; flex:1; min-height:0}
.page .kv{display:grid; grid-template-columns:140px 1fr; gap:6px 16px; align-content:start}
.page .kv b{font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--bronze); padding-top:3px}
.page .kv span{font-size:14px; line-height:1.5}
.page .callout{border-left:3px solid var(--ink); padding:8px 14px; font-size:17px; font-weight:600; line-height:1.4; margin-top:18px}
.page .fig{background:var(--bg); border:1px solid var(--hair); display:grid; place-items:center; overflow:hidden}
.page .fig svg{width:100%; height:100%}
.page .cap{font-size:11px; color:var(--gray); margin-top:6px; letter-spacing:.04em}
.page .principles{list-style:none; margin:14px 0 0; padding:0; display:grid; gap:10px}
.page .principles li{display:grid; grid-template-columns:22px 1fr; gap:10px; font-size:14px; line-height:1.45}
.page .principles li b{color:var(--bronze)}
.page .frames{display:grid; grid-template-columns:repeat(4,1fr); gap:18px; flex:1; min-height:0}
.page .frame{display:flex; flex-direction:column; gap:8px; min-height:0}
.page .frame .fig{flex:1; min-height:0}
.page .frame b{font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--bronze)}
.page .frame p{font-size:13px}
.page .blocks{display:grid; grid-template-columns:repeat(3,1fr); gap:22px 28px; flex:1; align-content:start}
.page .blocks div b{display:block; font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--bronze); margin-bottom:6px}
.page .blocks div p{font-size:13.5px}
.page .test{border-top:2px solid var(--ink); padding-top:12px; display:flex; flex-direction:column; gap:10px}
.page .test h3{margin:0; font-size:15px; font-weight:700; line-height:1.3}
.page .test b{display:block; font-size:10px; letter-spacing:.14em; text-transform:uppercase; color:var(--bronze); margin-bottom:2px}
.page .test p{font-size:12.5px; line-height:1.45}
.page .gofrom{margin-top:auto; border-top:1px solid var(--hair); padding-top:14px; display:grid; grid-template-columns:1fr auto; gap:24px; align-items:center}
.page .gofrom ul{margin:6px 0 0; padding:0; list-style:none; display:flex; flex-wrap:wrap; gap:6px 14px; font-size:12px; color:#222}
.page .gofrom ul li::before{content:"→ "; color:var(--bronze)}
.page .cta{background:var(--ink); color:#fff; padding:14px 18px; font-weight:700; font-size:14px; max-width:260px; line-height:1.35}
.page.cover{justify-content:center; padding-left:96px}
.page.cover .mark{width:34px; height:44px; margin-bottom:28px}
.page.cover .mark .outline{fill:#fff; stroke:var(--ink); stroke-width:2}
.page.cover .sub{margin-top:18px; font-size:19px; color:#222; max-width:34ch; line-height:1.45}
.page.cover .date{margin-top:36px; font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:var(--gray)}
.page.cover .jr{font-size:11px; letter-spacing:.2em; text-transform:uppercase; color:var(--gray); margin-bottom:8px}

#s-review,#s-concept,#s-final,#s-pitch{padding-top:56px}
/* ---------- phone ---------- */
@media (max-width:640px){
  /* the dev readout is one compact line */
  /* checklist fits in the uppercase paradigms */
  body[data-paradigm="drafting"] #checklist, body[data-paradigm="marker"] #checklist, body[data-paradigm="pitch"] #checklist{font-family:var(--hand); font-size:16px; letter-spacing:0; text-transform:none; gap:12px}
  /* the sentence: lead above, the wheel gets the full width, ✓ is a thumb target */
  .sentence{flex-wrap:wrap; justify-content:flex-start; --row:2.3em; padding-left:8px; padding-right:8px; padding-top:0}
  .sentence .lead{width:100%; margin-bottom:.1em}
  .blankwrap{margin-top:calc(var(--row) * 2.4)}   /* the lead sits above the wheel's upper partials */
  .blankwrap{width:100%; justify-content:space-between; gap:10px}
  .picker{flex:1 1 auto; font-size:1em}
  .picker .opt:not(.cur){display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden}
  .confirm{width:44px; height:44px; flex:0 0 44px; margin-left:0}
  /* review: the walked story is one scrolling row; the CTA stays reachable */
  .walk-strip{flex-wrap:nowrap; overflow-x:auto; justify-content:flex-start; padding:4px 2px 8px; -webkit-overflow-scrolling:touch}
  .walk-strip .gp{flex:0 0 auto; width:88px; font-size:13px; padding:5px 6px 3px}
  .walk-strip .gp svg{height:28px}
  #to-concept{position:sticky; bottom:8px; align-self:center; box-shadow:0 8px 24px -12px rgba(43,42,39,.6)}
  /* concept: smaller sketches, thumb-sized card buttons */
  .dir svg{aspect-ratio:16/9}
  .dir .acts button{padding:10px 14px; font-size:13px}
  .game{padding:10px 12px}
  /* pitch: the lightbox is a scrollable page at a readable size, arrows at the bottom */
  .lightbox{place-items:start center; overflow:auto; padding:56px 0 90px}
  .lightbox .scroll{width:max-content}
  .lightbox .frame{transform-origin:0 0}
  .lightbox .nav{top:auto; bottom:calc(18px + env(safe-area-inset-bottom,0px)); transform:none; background:rgba(12,12,12,.55); border-radius:4px; padding:8px 18px; font-size:30px}
  .lightbox .pn{bottom:calc(30px + env(safe-area-inset-bottom,0px))}
}
@media (prefers-reduced-motion:reduce){:root{--m:.2}}

/* ---------------------------------------------------------------- product
   Pieces the click-through mockup did not need: real waiting, real failure,
   a real document and a way back in. */

/* a failure always says what happened and offers the way forward */
.error{position:fixed; left:50%; bottom:calc(72px + env(safe-area-inset-bottom,0px));
  transform:translateX(-50%); max-width:min(520px, calc(100vw - 32px)); z-index:40;
  background:var(--paper); border:1.5px solid var(--persimmon,#D4552B); border-radius:4px;
  padding:12px 16px; display:none; gap:14px; align-items:center;
  box-shadow:0 18px 40px -22px rgba(43,42,39,.5)}
.error.shown{display:flex}
.err-msg{flex:1; font-size:14px; line-height:1.4; color:var(--text)}
.err-retry{flex:0 0 auto; padding:8px 14px; border:1.5px solid var(--line); border-radius:3px;
  font-weight:600; font-size:13px; background:var(--line); color:var(--paper)}

/* the pitch preview IS the server's template, in a frame: what you read here
   is what the PDF renders */
.strip{width:min(1100px,100%); overflow:hidden; position:relative}
.pitch-frame{width:1056px; border:0; display:block; transform-origin:0 0; background:transparent}
#lb-scroll{display:grid; place-items:center}
#lb-frame{width:1056px; height:816px; border:0; background:#fff; transform-origin:0 0;
  box-shadow:0 40px 90px -30px rgba(0,0,0,.7)}

/* the done screen: the deliverable, the way back, and the bridge to nDirector */
.done-cta{display:inline-block; text-decoration:none; background:var(--line); color:var(--paper);
  padding:12px 18px; border-radius:3px; font-weight:700; font-size:14px}
#again, #copy-link{border:1px solid var(--rule,#DCDCDC); background:transparent; color:var(--muted);
  padding:10px 14px; border-radius:3px; font-size:13px; font-weight:600}
#again:hover, #copy-link:hover{color:var(--text); border-color:var(--line)}
.email-form{display:flex; gap:8px; margin-top:6px; width:min(420px,100%)}
.email-form input{flex:1; border:1px solid var(--rule,#DCDCDC); border-radius:3px; padding:10px 12px;
  font-size:14px; background:var(--paper); color:var(--text)}
.email-form button{padding:10px 16px; border-radius:3px; background:var(--line); color:var(--paper);
  font-weight:600; font-size:13px; border:0}
.email-thanks{margin:0; font-size:14px; color:var(--muted)}
.done-actions{display:flex; gap:10px; flex-wrap:wrap; justify-content:center; align-items:center}

/* the file input is opened from the (+) menu, never shown */
#file-in{position:absolute; width:1px; height:1px; opacity:0; pointer-events:none}

@media (max-width:640px){
  .error{bottom:calc(64px + env(safe-area-inset-bottom,0px))}
  .strip{width:100%}
  .email-form{width:100%}
}

/* the download is a link; while the document is still rendering it is inert */
a#dl{text-decoration:none; display:inline-flex; align-items:center}
a#dl.waiting{opacity:.55; pointer-events:none}
