/* ===========================================================================
   THE NINE HANDS
   ---------------------------------------------------------------------------
   One handwriting face per pilot, bundled as latin-subset woff2 by
   tools/get-hands.mjs (which records the licence and the per-pilot argument).

   ⚠️ WHY FILES AND NOT A NINE-WAY SYSTEM STACK. `--hand` below is a stack, and
   a stack is the right answer for ONE hand: every machine owns something
   handwritten, so it always resolves to something handwritten. It cannot give
   nine DIFFERENT hands. Nine stacks would look like nine faces on this Windows
   box and collapse to one terminal `cursive` on a Mac, a phone, or anybody
   else's computer — and nothing on screen would say so. A design that only
   works on the author's machine is not a design. 237 KB, against a 53 MB
   deploy, buys the idea actually leaving the building.

   THE FICTION IT BUYS. The screen is a form: printed headings in the game's
   voice, answers filled in by hand. Nine hands means nine people filled in
   nine forms, which is a stronger read than one person labelling nine
   photographs, and it costs no words. HORNET's is bubbly and childish because
   she is the youngest by years; MARAUDER writes in marker because she writes
   on things that are not paper; VESPER's is barely pressed into the page.

   `--handScale` exists because these nine were not drawn to one another. At a
   common font-size Sacramento sets tiny and Permanent Marker sets huge, so
   each carries a correction that makes 56px mean roughly the same height for
   all nine. Without it, swapping a hand silently re-lays out the column.
   =========================================================================== */
@font-face{font-family:"h-architects-daughter";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/architects-daughter.woff2) format("woff2")}
@font-face{font-family:"h-rock-salt";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/rock-salt.woff2) format("woff2")}
@font-face{font-family:"h-just-another-hand";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/just-another-hand.woff2) format("woff2")}
@font-face{font-family:"h-sacramento";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/sacramento.woff2) format("woff2")}
@font-face{font-family:"h-patrick-hand";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/patrick-hand.woff2) format("woff2")}
@font-face{font-family:"h-gloria-hallelujah";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/gloria-hallelujah.woff2) format("woff2")}
@font-face{font-family:"h-permanent-marker";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/permanent-marker.woff2) format("woff2")}
@font-face{font-family:"h-shadows-into-light";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/shadows-into-light.woff2) format("woff2")}
@font-face{font-family:"h-cedarville-cursive";font-style:normal;font-weight:400;
  font-display:swap;src:url(../../assets/fonts/hands/cedarville-cursive.woff2) format("woff2")}

/* Setting `--hand` on a CONTAINER rather than naming a font on each element is
   the whole trick: every rule in this file already reads `var(--hand)`, so one
   attribute on a wrapper re-letters the call sign, the frame line, her quote
   and every answer on the form at once, and a new handwritten element inherits
   her hand without anybody remembering to wire it.

   ⚠️ The scales are not guesses. They are cap-height ratios against the system
   stack at the same px: Just Another Hand is a condensed poster face and sets
   about 40% short, Sacramento is a small-x-height script, Permanent Marker and
   Gloria Hallelujah both set large. Change a font, re-measure the number. */
#ui [data-hand="architects-daughter"]{--hand:"h-architects-daughter",cursive;--handScale:.94}
#ui [data-hand="rock-salt"]          {--hand:"h-rock-salt",cursive;          --handScale:.72}
#ui [data-hand="just-another-hand"]  {--hand:"h-just-another-hand",cursive;  --handScale:1.42}
#ui [data-hand="sacramento"]         {--hand:"h-sacramento",cursive;         --handScale:1.30}
#ui [data-hand="patrick-hand"]       {--hand:"h-patrick-hand",cursive;       --handScale:1.02}
#ui [data-hand="gloria-hallelujah"]  {--hand:"h-gloria-hallelujah",cursive;  --handScale:.82}
#ui [data-hand="permanent-marker"]   {--hand:"h-permanent-marker",cursive;   --handScale:.86}
#ui [data-hand="shadows-into-light"] {--hand:"h-shadows-into-light",cursive; --handScale:1.06}
#ui [data-hand="cedarville-cursive"] {--hand:"h-cedarville-cursive",cursive; --handScale:1.16}

/* ===========================================================================
   screens.css — the bubblegum facade, as real DOM.
   ---------------------------------------------------------------------------
   Lifted, near-verbatim, out of tools/ui-mock/option-a.html. That file is the
   source of truth for look, motion and sound; this one is the shipping copy of
   its paint layer. Where the two differ, the differences are listed at the top
   of each block and there are only four of them:

     1. EVERYTHING IS SCOPED UNDER `#ui`. The mock owned the whole document —
        it set `html,body`, it styled a lab bench, it defined bare `.screen`.
        This file may not touch anything outside the UI layer, or a rule
        written for a sticker starts applying to the fatal-error pane.
     2. THE PAPER IS FULL-BLEED; THE COMPOSITION IS NOT. The mock was a fixed
        1280x720 frame in a web page. The game fills the window. See THE STAGE.
     3. `:root` VARIABLES MOVED TO `#ui`. Same names, same values, no leak.
     4. DECO IMAGES ARE BACKGROUNDS, NOT <img>. One line per asset at the foot
        of this file, so every path into assets/ lives in exactly one place and
        JS names a sticker rather than a filename. `filter:drop-shadow` follows
        a background-image's alpha, so the die-cut shadow is unchanged.

   Architecture, from SCOPE-facade.md §3: the menu is pink because somebody
   decorated it; the cockpit is green because nobody decorates instruments.
   Menus are DOM. The cockpit is canvas. That is why this file exists.
   =========================================================================== */

#ui{
  /* TYPE. Web-safe only. Ink Free ships with Win10/11 and is the good one;
     Segoe Print and Bradley Hand are the Mac/older fallbacks; Comic Sans is
     last because it is the only guaranteed one, not because it is wanted.
     Trebuchet is the "printed form" voice — humanist, slightly warm, and
     crucially NOT the handwriting, so the two layers stay legible as two.
     ⚠️ The game bundles Orbitron and Rajdhani and neither is a hand. Nothing
     here may fall back to them: a menu set in the HUD's face is the cockpit
     eating the decoration, which is the one thing the design forbids. */
  --hand:"Ink Free","Segoe Print","Bradley Hand ITC","Comic Sans MS",cursive;
  --form:"Trebuchet MS","Segoe UI",Tahoma,sans-serif;
  /* Every hand is measured against the system stack's size, so switching one in
     does not resize the column. Overridden per pilot below. */
  --handScale:1;

  /* Paper first. The pinks are things ON the paper, so the paper wins ties. */
  --paper:#faefe4;
  --paper-2:#f3e2d3;
  --ink:#4a4039;           /* ballpoint brown-black, never pure #000 */
  --print:#8d8279;         /* the printed form's grey — the game underneath */
  --rule:#d9c9ba;

  --pink:#ff5fa2;          /* the marker. Saturated, opaque, felt-tip. */
  --pink-soft:#ffc2dc;
  --pink-pale:#ffe6f0;
  --gold:#ffc846;

  /* THE CLASH. Decora is not "more pink". Six saturated colours at once,
     deliberately not harmonised, because a decorated object accumulates
     colours one bag at a time and nobody reconciles them afterwards. If they
     ever start looking tasteful together, one of them is wrong. */
  --mint:#2fd9ab;
  --lemon:#ffd93b;
  --lilac:#b07cff;
  --tang:#ff8a3d;
  --sky:#49b8ff;
  --cherry:#ff4d6d;

  /* Bouncy overshoot. Used on every press in the file so the whole interface
     has ONE hand — a control that returns linearly next to one that overshoots
     reads as two different products. */
  --bounce:cubic-bezier(.34,1.66,.5,1);

  /* THE STAGE SCALE, written by title.js every resize. Anything measured in
     paper units rather than in composition units multiplies by it — see the
     ruled lines and the grain. Without it a 33px rule stays 33px while the
     handwriting on top of it halves, and the sheet stops being one object. */
  --s:1;

  font-family:var(--form);
  color:var(--ink);
}

/* A screen is opaque and it clips. The mock's stage clipped at 1280x720 and a
   good deal of the composition hangs off the edge on purpose — the candy cane
   at x-26, the charms at x1240 — so losing the clip does not "show more", it
   shows the parts that were meant to be cropped. */
#ui .screen{overflow:hidden}

/* ---------------------------------------------------------------------------
   THE STAGE — the one thing the mock could not answer and a game must.

   The mock was a fixed 1280x720 frame in a fluid page, scaled to fit and
   letterboxed against the browser's own background. A game fills the window,
   and letterboxing a menu against the corridor would put the play field back
   on screen behind the paper — which is exactly the register split this whole
   design exists to keep apart.

   So the answer is split in two, because the artefact is two things:

     THE PAPER IS FULL-BLEED. It is a substrate, it has no composition, and it
     is the one layer that must reach every corner or the illusion is a card
     floating on a starfield.

     THE COMPOSITION IS CONTAIN-FITTED. 1280x720, scaled by min(w/1280,h/720)
     and centred. Every hand-placed coordinate in the mock survives unchanged,
     nothing is ever cropped by a window that is the wrong shape, and the
     density-at-the-edges law still reads because the edges it crowds are the
     sheet's edges.

   On a 16:9 window the two coincide exactly and this is the mock. Off 16:9 the
   sheet is simply bigger than the decorated area, which is what a sheet of
   paper with a drawing on it looks like.
--------------------------------------------------------------------------- */
#ui .stage{
  position:absolute;left:50%;top:50%;width:1280px;height:720px;
  translate:-50% -50%;scale:var(--s);
  overflow:hidden;
}
/* The slide on a screen change happens HERE and not on .stage, because .stage
   owns the centring translate and an animation on `translate` would wipe it. */
#ui .stage > .plate-slide{position:absolute;inset:0}

/* ---------------------------------------------------------------------------
   THE PAPER — the substrate everything else is stuck to.
   Three stacked layers, cheapest last: a grain (inline SVG turbulence, no
   file), the ruled lines of the form, and the warm base. The grain matters
   more than it looks: a perfectly flat cream reads as "beige UI", and grain is
   the entire difference between paper and a background-color.
--------------------------------------------------------------------------- */
#ui .paper{position:absolute;inset:0;background:var(--paper)}
#ui .paper::before{content:"";position:absolute;inset:0;opacity:.55;
  background:repeating-linear-gradient(to bottom,
    transparent 0 calc(33px * var(--s)),
    var(--rule) calc(33px * var(--s)) calc(34px * var(--s)));
  mask-image:linear-gradient(to bottom,transparent 0,#000 12%,#000 88%,transparent 100%)}
#ui .paper::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:.5;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.32'/%3E%3C/svg%3E");
  background-size:calc(180px * var(--s)) calc(180px * var(--s));
  mix-blend-mode:multiply}
/* Corner shading — paper is never lit evenly, and the eye reads even light as
   "screen". */
#ui .paper .vig{position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 50% 30%,transparent 40%,#00000018 100%)}

/* ---------------------------------------------------------------------------
   WASHI TAPE
   Every card is TAPED down rather than floated, because a drop shadow says
   "layer" and tape says "somebody put this here". Stripes are a gradient; the
   torn ends are a clip-path with a couple of nicks in it.
--------------------------------------------------------------------------- */
#ui .tape{position:absolute;width:112px;height:30px;opacity:.9;
  background:repeating-linear-gradient(46deg,#ffb4d4 0 9px,#ffd9e8 9px 18px);
  box-shadow:0 2px 5px #0000002e;
  clip-path:polygon(3% 6%,97% 0%,100% 92%,96% 100%,60% 94%,26% 100%,0% 95%)}
#ui .tape.mint{background:repeating-linear-gradient(46deg,#a9ecd4 0 9px,#dcfaee 9px 18px)}
#ui .tape.gold{background:repeating-linear-gradient(46deg,#ffde9a 0 9px,#fff2d3 9px 18px)}
#ui .tape.plain{background:linear-gradient(#fff9,#fff3);border:1px solid #ffffff88}
/* The rest of the roll. Same stripe, five more colours, because a person with
   one roll of washi tape has six rolls of washi tape. */
#ui .tape.lilac{background:repeating-linear-gradient(46deg,#cdb0ff 0 9px,#ece0ff 9px 18px)}
#ui .tape.lemon{background:repeating-linear-gradient(46deg,#ffe98c 0 9px,#fff8cf 9px 18px)}
#ui .tape.sky  {background:repeating-linear-gradient(46deg,#a8dcff 0 9px,#dcf1ff 9px 18px)}
#ui .tape.tang {background:repeating-linear-gradient(46deg,#ffc593 0 9px,#ffe6d1 9px 18px)}
/* Dots and checks, not stripes — variety of PATTERN at the same time as
   multiplicity of colour is what stops six tapes reading as one striped
   system. */
#ui .tape.dots{background:#fff2f8;
  background-image:radial-gradient(circle,var(--c,var(--pink)) 2.4px,transparent 2.6px);
  background-size:11px 11px}
#ui .tape.check{background:
  repeating-linear-gradient(0deg,var(--c,var(--mint)) 0 7px,transparent 7px 14px),
  repeating-linear-gradient(90deg,var(--c,var(--mint)) 0 7px,#fff 7px 14px);
  background-blend-mode:multiply;opacity:.72}

/* ===========================================================================
   HARDWARE
   ---------------------------------------------------------------------------
   The part of decora that is not printed and not a sticker: bows, clips, pins,
   beads, pompoms, charms on chains. All of it is DRAWN here in CSS or one
   inline SVG, and none of it is an asset. A platformer tile photographed at
   64px is a picture of a bow; a box-shadow bow is a bow — it takes the page's
   own light, it can be any of the six clash colours from one rule, and it
   costs no bytes.

   Everything here is inert: pointer-events:none, no role, no label. It is
   furniture. A bow must never be a button.
   =========================================================================== */

/* BOW — two lobes, two tails, a knot. The knot is the whole thing: two lobes
   alone read as a butterfly. The white die-cut margin is a chain of
   drop-shadows on the PARENT, not a border on each part; a border per part
   outlines every internal seam too, and at 26px the bow stops being one object
   and becomes three white pills. */
#ui .bow{position:absolute;width:var(--w,42px);height:calc(var(--w,42px) * .74);
  pointer-events:none;
  filter:drop-shadow(1.6px 0 0 #fff) drop-shadow(-1.6px 0 0 #fff)
         drop-shadow(0 1.6px 0 #fff) drop-shadow(0 -1.6px 0 #fff)
         drop-shadow(0 3px 3px rgba(80,50,60,.34))}
/* Lobes are lopsided ellipses tipped outward, not circles: the asymmetric
   border-radius is what makes the outer edge of a loop fatter than the inner
   edge, which is the only bit of a bow the eye actually checks. */
#ui .bow i{position:absolute;top:0;width:56%;height:66%;background:var(--c,var(--pink));z-index:1}
#ui .bow i:first-of-type{left:-3%;border-radius:66% 34% 44% 56%/64% 58% 42% 36%;rotate:-15deg}
#ui .bow i:last-of-type {right:-3%;border-radius:34% 66% 56% 44%/58% 64% 36% 42%;rotate:15deg}
#ui .bow b{position:absolute;left:50%;top:42%;width:27%;height:33%;translate:-50% -50%;
  border-radius:42%;background:var(--c,var(--pink));z-index:3;
  box-shadow:0 0 0 2px rgba(255,255,255,.95)}
#ui .bow::before,#ui .bow::after{content:"";position:absolute;top:40%;width:21%;height:58%;
  background:var(--c,var(--pink));border-radius:10% 10% 44% 44%;z-index:0}
#ui .bow::before{left:29%;rotate:21deg} #ui .bow::after{right:29%;rotate:-21deg}

/* CLIP — a plastic clip biting an edge. Written to be used in ROWS and never
   alone. Six identical clips is one decision made six times; six different
   charms is a designer picking six charms, and only the first of those is what
   a decorated object looks like. */
#ui .clip{position:relative;flex:none;width:24px;height:36px;
  background:var(--c,var(--pink));border-radius:6px 6px 4px 4px;
  box-shadow:0 -3px 0 rgba(255,255,255,.45) inset,
             0 -10px 0 rgba(0,0,0,.17) inset,
             0 3px 6px rgba(60,40,50,.34)}
#ui .clip::before{content:"";position:absolute;left:50%;top:5px;translate:-50% 0;
  width:5px;height:15px;border-radius:3px;background:rgba(255,255,255,.62)}
#ui .clip::after{content:"";position:absolute;left:3px;right:3px;bottom:5px;height:4px;
  border-radius:3px;background:rgba(255,255,255,.4)}
#ui .cliprow{position:absolute;display:flex;gap:var(--g,60px);pointer-events:none}

/* BEADS — a strung row. transform-origin is the knot at one end, so the whole
   string swings as ONE object. Beads that each wobble independently read as
   nine animations; beads that swing together read as a thing on a string. */
#ui .beads{position:absolute;display:flex;align-items:center;gap:3px;
  transform-origin:0 50%;pointer-events:none}
#ui .beads.v{flex-direction:column;transform-origin:50% 0}
#ui .beads::before{content:"";position:absolute;left:0;right:0;top:50%;height:2px;
  translate:0 -1px;background:#cfc0b1}
#ui .beads.v::before{left:50%;right:auto;top:0;bottom:0;width:2px;height:auto;translate:-1px 0}
/* position:relative only so tree order (string first, beads after) is also
   paint order. Without it the absolutely-positioned string paints on top. */
#ui .beads i{position:relative;flex:none;width:var(--b,12px);height:var(--b,12px);
  border-radius:50%;background:
    radial-gradient(circle at 33% 28%,rgba(255,255,255,.85),transparent 46%),
    var(--c,var(--pink));
  box-shadow:0 1px 2px rgba(60,40,50,.42)}

/* DANGLER — a charm on a short chain hanging off an edge. transform-origin is
   50% 0, the ring: a charm that rotates about its middle is a spinning logo,
   and a charm that rotates about the ring is a hanging object. */
#ui .dangle{position:absolute;transform-origin:50% 0;pointer-events:none;
  display:flex;flex-direction:column;align-items:center}
#ui .dangle .lnk{width:5px;height:var(--h,26px);border-radius:3px;
  background:repeating-linear-gradient(to bottom,#dfe3ea 0 3px,#8d929c 3px 6px)}
#ui .dangle .chm{width:var(--w,30px);height:var(--w,30px);border-radius:50%;
  background:var(--c,var(--pink));border:3px solid #fff;box-sizing:border-box;
  box-shadow:0 2px 5px rgba(60,40,50,.42);display:grid;place-items:center;
  font:calc(var(--w,30px) * .52)/1 var(--form);color:#fff;padding-bottom:2px}

/* POMPOM — one circle plus eight small copies of itself in box-shadow, ringed
   just outside its own edge. Sizing is the entire difference between a pompom
   and a hexagon: six large circles in a ring make a polygon and the eye reads
   the flats. Eight lumps at 40% of the base diameter read as a bobble. */
/* --- skull ---------------------------------------------------------------
   A cute skull, built the way the bow and the pom are built: HTML elements and
   border-radius, no image. That is not thrift, it is the house idiom — every
   piece of hardware on these screens is CSS, which is why they all take a
   `--c` and all inherit the same white sticker outline.

   ⚠️ IT HAD TO BE DRAWN RATHER THAN FOUND. The asset library has thirty-odd
   skull icons and every one of them is the horror register: fangs, cracks,
   sockets like pits. Sticking a bow on one of those gives you a horror icon
   wearing a bow, which reads as a joke about the game rather than a thing in
   it. Cute is a PROPORTION problem, not an accessory problem — a huge round
   cranium, a tiny jaw, eyes far apart and low, is a baby skull, and it is
   cute before anything is tied to it. Then the bow lands as decoration
   instead of as punchline.

   It also earns its place: the facade is a schoolgirl's, and a small skull
   among the hearts is exactly the taste of the person who decorated this — she
   is flying a warplane, and SCOPE-facade §2 wants the sweetness to have one
   edge in it somewhere. Put it near a bow; never near a name. */
#ui .skull{position:absolute;width:var(--w,30px);height:calc(var(--w,30px) * 1.08);
  pointer-events:none;
  filter:drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff)
         drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff)
         drop-shadow(0 3px 3px rgba(80,50,60,.3))}
/* The cranium: wider than it is tall, and flattened at the bottom where the
   jaw meets it. 62% of the height, so the jaw gets a third — a realistic skull
   is nearly all cranium and reads as a medical diagram. */
#ui .skull .cr{position:absolute;left:0;top:0;width:100%;height:66%;
  background:var(--c,#fffdfa);border-radius:50% 50% 44% 44%/56% 56% 44% 44%}
/* The jaw is NARROWER and SHORTER than the cranium and sits under it with a
   notch of paper showing at each side. Those two notches are what stop the
   silhouette being an egg. */
#ui .skull .jw{position:absolute;left:28%;top:62%;width:44%;height:28%;
  background:var(--c,#fffdfa);border-radius:24% 24% 44% 44%/16% 16% 64% 64%}
/* THREE TEETH, AS TWO SEPARATIONS. The teeth are the jaw itself; what is drawn
   is the two lines BETWEEN them, which is how a tooth row actually reads and
   costs one gradient instead of three elements.

   ⚠️ The first version used one bar plus two `em`-offset box-shadows, and it
   rendered as a single grey slot: `.skull` sets no font-size, so `em` resolved
   against the inherited 13px and the offsets collapsed at every size the game
   uses. Percentages of the jaw are the only units here that scale with `--w`,
   which is the whole reason this object is built out of percentages. */
#ui .skull .jw::after{content:"";position:absolute;left:22%;right:22%;top:20%;height:54%;
  background:linear-gradient(90deg,#0000 0 30%,#7a6a7855 30% 38%,
                             #0000 38% 62%,#7a6a7855 62% 70%,#0000 70%)}
/* Eyes low and far apart, but NOT enormous. The first pass had them at 28% and
   the thing read as a plush panda rather than a skull — past about a quarter of
   the width the sockets stop being sockets and become anime eyes, and the
   silhouette loses the one feature that says what it is. 24% keeps it cute and
   keeps it a skull. */
#ui .skull i{position:absolute;top:31%;width:24%;height:29%;border-radius:50%;
  background:#5a4a58}
#ui .skull i:first-of-type{left:11%}
#ui .skull i:last-of-type{right:11%}
/* One highlight per socket, both on the same side, because two lights is two
   light sources and the eye notices. */
#ui .skull i::after{content:"";position:absolute;left:22%;top:16%;width:34%;height:32%;
  border-radius:50%;background:rgba(255,255,255,.72)}
/* The nose: a soft heart rather than the usual inverted triangle. A triangle is
   the most skull-like mark on a skull and the cheapest one to give up. */
#ui .skull b{position:absolute;left:50%;top:52%;translate:-50% 0;width:15%;height:12%;
  background:#5a4a58;border-radius:50% 50% 50% 50%/70% 70% 34% 34%;rotate:180deg}
/* A blush, because it costs one element and it is the whole register. */
#ui .skull .bl{position:absolute;top:44%;width:16%;height:9%;border-radius:50%;
  background:#ff9ec4;opacity:.72}
#ui .skull .bl.l{left:4%} #ui .skull .bl.r{right:4%}

#ui .pom{position:absolute;width:var(--w,18px);height:var(--w,18px);font-size:var(--w,18px);
  border-radius:50%;pointer-events:none;
  background:radial-gradient(circle at 34% 28%,rgba(255,255,255,.5),transparent 46%),
             var(--c,var(--lemon));
  box-shadow:
        0 -.38em 0 -.3em var(--c,var(--lemon)),  .27em -.27em 0 -.3em var(--c,var(--lemon)),
     .38em     0 0 -.3em var(--c,var(--lemon)),  .27em  .27em 0 -.3em var(--c,var(--lemon)),
        0  .38em 0 -.3em var(--c,var(--lemon)), -.27em  .27em 0 -.3em var(--c,var(--lemon)),
    -.38em     0 0 -.3em var(--c,var(--lemon)), -.27em -.27em 0 -.3em var(--c,var(--lemon)),
        0 3px 5px rgba(60,40,50,.3)}

/* SAFETY PIN — the one thing here that is an SVG, because a pin is a line
   drawing and a line drawing wants a stroke. Steel, never a clash colour: the
   pin is the honest bit of hardware on a page of sweets, and it is doing a
   job. Inline data-URI, so still no file. */
#ui .pin{position:absolute;width:var(--w,20px);height:calc(var(--w,20px) * 2.7);
  pointer-events:none;filter:drop-shadow(0 2px 2px rgba(60,40,50,.4));
  background:center/contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 68'%3E%3Cg fill='none' stroke='%23b9bdc7' stroke-width='3.4' stroke-linecap='round'%3E%3Cpath d='M8 14V46'/%3E%3Cpath d='M8 46a6.6 6.6 0 0 0 8.6 5 6.6 6.6 0 0 0 1.4-9.4'/%3E%3Cpath d='M17 44V18'/%3E%3C/g%3E%3Crect x='7.5' y='4' width='13' height='14' rx='5' fill='%23ced2db' stroke='%23a9adb7' stroke-width='1.6'/%3E%3C/svg%3E")}

/* LACE — scalloped trim. It only ever runs along an EDGE, which is the whole
   reason it reads as trim rather than as a pattern somebody tiled. */
#ui .lace{position:absolute;height:var(--h,15px);pointer-events:none;
  background:radial-gradient(circle at var(--h,15px) 0,
    var(--c,#fffdf8) calc(var(--h,15px) - 2px),transparent calc(var(--h,15px) - 1px));
  background-size:calc(var(--h,15px) * 2) 100%;
  filter:drop-shadow(0 2px 2px rgba(80,50,60,.2))}

/* PINKING — the zigzag a pair of pinking shears leaves. Same job as lace, a
   different hand: shears are what you use when you do not have lace. */
#ui .zig{position:absolute;height:9px;pointer-events:none;background:var(--c,var(--lemon));
  -webkit-mask:conic-gradient(from -45deg at 50% 100%,#000 0 90deg,transparent 0) 0 0/18px 100%;
          mask:conic-gradient(from -45deg at 50% 100%,#000 0 90deg,transparent 0) 0 0/18px 100%}
#ui .zig.up{-webkit-mask:conic-gradient(from 135deg at 50% 0,#000 0 90deg,transparent 0) 0 0/18px 100%;
                    mask:conic-gradient(from 135deg at 50% 0,#000 0 90deg,transparent 0) 0 0/18px 100%}

/* PUNCH HOLES + MARGIN RULE — not decoration at all, which is why they are
   here. They say the substrate is a SHEET, out of a binder, and a sheet is the
   thing all the decoration is stuck to. The hole shows the desk colour because
   it is a hole — and here the desk is the game, so it shows the corridor. */
#ui .punch{position:absolute;left:16px;top:0;bottom:0;width:22px;pointer-events:none;
  display:flex;flex-direction:column;justify-content:space-evenly;align-items:center}
#ui .punch i{width:17px;height:17px;border-radius:50%;background:#2b2029;
  box-shadow:0 1px 0 rgba(255,255,255,.8),inset 0 2px 4px rgba(0,0,0,.55)}
#ui .margin{position:absolute;left:54px;top:0;bottom:0;width:2px;pointer-events:none;
  background:#ff9dc4;opacity:.6}

/* STICKER STACK — layers by occlusion. Decora is not "many stickers", it is
   stickers ON stickers: a thing half-covered by another thing is the only
   cheap way to say two people, or one person twice, and depth is what stops
   density becoming wallpaper. */
#ui .stack{position:absolute;pointer-events:none}
#ui .stack .deco,#ui .stack .bow,#ui .stack .pom{position:absolute}

/* ---------------------------------------------------------------------------
   THE HAND
   Titles are written, not set. `-webkit-text-stroke` is not used: a felt-tip
   has no outline. The slight rotation is the whole trick — a heading at 0deg
   in a script font reads as a font, and at -1.6deg it reads as a hand.
--------------------------------------------------------------------------- */
#ui .hand{font-family:var(--hand);color:var(--pink);line-height:.98}
#ui .hand.ink{color:var(--ink)}
#ui .formlabel{font:700 10px/1 var(--form);letter-spacing:.22em;color:var(--print);
  text-transform:uppercase}

/* --- die-cut sticker buttons ---------------------------------------------
   A sticker is a shape with a white die-cut margin and a hard, short shadow
   because it is 0.3mm off the page. Not a soft UI shadow — a real one.

   CHANGED FROM THE MOCK: these are real <button> elements. In a mock a div
   that looks like a button is a picture of a button; in a game it is a control
   a keyboard cannot reach and a screen reader cannot name. The `appearance`
   and `font:inherit` resets are the whole cost of the upgrade.               */
#ui .sticker{position:relative;display:inline-flex;align-items:center;gap:10px;
  padding:11px 24px 12px;border-radius:999px;background:var(--pink);
  color:#fff;font:700 17px/1 var(--form);letter-spacing:.06em;cursor:pointer;
  border:5px solid #fff;box-shadow:0 3px 0 #d5417f,0 6px 10px #0000002e;
  -webkit-appearance:none;appearance:none;text-align:left;
  /* translate/rotate/scale, never `transform` — see MOTION for why. Overshoot
     on the way IN, so the button arrives past where it is going and settles
     back; that is the difference between a UI that responds and one that feels
     sprung. */
  transition:translate .19s var(--bounce),rotate .19s var(--bounce),
             scale .19s var(--bounce),box-shadow .12s ease}
#ui .sticker:hover{translate:0 -3px;rotate:-1.6deg;scale:1.035}
/* Keyboard reachability has to be VISIBLE or it is not reachability. The ring
   is the pink marker, offset outside the die-cut white, so it reads as one
   more thing pressed onto the page rather than as a browser artefact. */
#ui .sticker:focus-visible{outline:3px solid var(--pink);outline-offset:4px;
  translate:0 -3px;rotate:-1.6deg;scale:1.035}
/* SQUASH. A press flattens the thing: wider, shorter, lower. A press that only
   moves down is a shadow trick; a press that squashes has mass. `.press` is
   set by JS for 110ms so the squash survives a click that releases instantly —
   a real click releases in about 40ms and an :active squash that short is a
   flicker. */
#ui .sticker:active,#ui .sticker.press{translate:0 4px;rotate:0deg;scale:1.07 .88;
  box-shadow:0 1px 0 #d5417f,0 2px 4px #00000024;
  transition-duration:.06s;transition-timing-function:ease-out}
#ui .sticker.ghost{background:#fff;color:var(--pink);box-shadow:0 3px 0 #e7d3c2,0 6px 10px #0000001f}
#ui .sticker.small{font-size:13px;padding:7px 16px 8px;border-width:4px}
/* CLASH ON CONTROLS, with a ceiling. The primary action stays pink — it is the
   one thing she wanted you to press. The others take the other five colours,
   but only on the EDGE and the WORD, never the face: a white face is what
   keeps coloured buttons readable, and it is also true to the object, because
   die-cut sticker sheets come white and the colour is the print. */
#ui .sticker.tint{background:var(--c);box-shadow:0 3px 0 var(--e),0 6px 10px #0000002e}
#ui .sticker.tint:active,#ui .sticker.tint.press{box-shadow:0 1px 0 var(--e),0 2px 4px #00000024}
#ui .sticker.ghost.tint{background:#fff;color:var(--c);
  box-shadow:0 3px 0 var(--e),0 6px 10px #0000001f}
/* A bow safety-pinned to the left of a label. Hardware ON a control is allowed
   as long as it is not the control — this one is inside the button so it moves
   with it, and it is still pointer-events:none. */
#ui .sticker .bow{position:relative;flex:none;--w:26px}

/* scattered decoration */
#ui .deco{position:absolute;pointer-events:none;
  filter:drop-shadow(0 2px 2px rgba(80,50,60,.28))}
/* Every deco is a background rather than an <img>, so the asset paths are all
   in one place (foot of this file) and JS names a sticker, not a filename.
   An <img> gets its height from the file; a div does not, so the two intrinsic
   aspects in the set are declared here. Everything then sets `width` alone,
   exactly as the mock did, and the box is the same box. */
#ui .deco[data-img]{background:center/contain no-repeat}
#ui .deco[data-img^="candy/"]{aspect-ratio:1}                 /* all 70x70 */
#ui .deco[data-img^="flat/"],
#ui .deco[data-img^="sticker/"]{aspect-ratio:32 / 38}         /* all 32x38 */

/* the green art, never recoloured — only ever FRAMED (SCOPE §4) */
#ui .pinup{image-rendering:pixelated;display:block}

/* --- polaroid ------------------------------------------------------------ */
#ui .polaroid{position:absolute;background:#fffdfa;padding:10px 10px 0;
  box-shadow:0 4px 12px #0000002b,0 1px 0 #fff inset;border-radius:7px}
/* The photo well is ROUNDED, and only slightly. A real print has square
   corners, so this is a lie — but a 6px radius on a dark rectangle sitting
   inside a white frame is the difference between a photo and a hole cut in
   the page, and every other painted box on this sheet is rounded. At more
   than about 8 it stops reading as a print at all. */
/* ⚠️ THE WELL IS WHITE NOW, AND THE OLD COMMENT WAS RIGHT WHEN IT WAS WRITTEN.

   It used to be #20182a, and the reason was sound: "the pinups are
   green-on-transparent; on cream they are illegible, on near-black they glow."
   That described the ADULT set in assets/pinups/ — flat green phosphor
   figures. The screen now draws the CHIBI set (assets/pinups-chibi/), which is
   full colour, fully rendered and outlined, and full-colour art on near-black
   is a hole cut in a scrapbook page. The girls read better on white than they
   ever did on the dark, and the page stops having nine dark rectangles
   punched through it.

   The old rule survives where it still applies: the GREEN art is still never
   recoloured, only framed. What changed is which art is in the frame.

   White alone would dissolve into the print's own #fffdfa, so the well is a
   half-step cooler with a hairline inset — enough to read as a photograph
   sitting inside a border, which is the job the dark rectangle used to do. */
#ui .polaroid .win{background:#fff;overflow:hidden;position:relative;border-radius:6px;
  display:flex;align-items:flex-end;justify-content:center;
  box-shadow:inset 0 0 0 1px #e8dcd0,inset 0 2px 7px #b9a89855}
/* A breath of warmth up from the floor of the frame, so a figure standing on
   the bottom edge is standing on something rather than floating on paper. */
#ui .polaroid .win::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(72% 58% at 50% 104%,#ffd9ea88,transparent 72%)}
#ui .polaroid .cap{font-family:var(--hand);color:var(--ink);text-align:center;
  font-size:17px;padding:5px 0 7px}

/* Head-crop mug, used wherever a pilot is a face rather than a figure. The
   offsets that make it land on a face and not on a hatch are measured in
   src/ui/pinups.js, off the alpha channel. */
#ui .mug{border-radius:50%;background:#1a1426;overflow:hidden;position:relative;
  border:4px solid #fff;box-shadow:0 2px 5px #0003}
#ui .mug img{position:absolute}

/* =========================================================================
   1 — TITLE
   ========================================================================= */
#ui #ui-title .plate{position:absolute;left:78px;top:74px;width:640px}
#ui #ui-title h1{margin:0;font-family:var(--hand);font-size:118px;line-height:.84;
  color:var(--pink);transform:rotate(-2.2deg);
  text-shadow:3px 4px 0 #fff,6px 8px 0 #ffd0e2}
#ui #ui-title h1 em{font-style:normal;color:var(--ink)}
/* One block per line of `theme.title`, each only as wide as its own word. The
   mock hard-coded "ALL / HANDS!" and hard-coded the marker stroke under it at
   474x13 @ y186 to match. A title that comes out of the theme can be one word
   or three, so the stroke is MEASURED off the last line after layout (see
   title.js) rather than being a number that was right once. */
#ui #ui-title h1 .ln{display:block;width:fit-content}
/* 186px/474px are the mock's numbers for its own two-line "ALL HANDS!" and are
   only ever the fallback: title.js measures the rendered h1 and overwrites both
   inline, because the words now come from the theme. */
#ui #ui-title .under{position:absolute;left:6px;top:186px;width:474px;height:13px;
  background:var(--gold);opacity:.65;transform:rotate(-1.4deg);border-radius:8px;
  /* hand-drawn underline: a marker stroke thins at both ends */
  mask-image:linear-gradient(90deg,transparent,#000 6%,#000 92%,transparent)}
/* The subheads were losing to a 100px title. Both are stronger now, and they
   are strengthened DIFFERENTLY on purpose — the whole screen is two voices,
   and making them both merely bigger would have collapsed them into one.

   The hand gets SIZE and WEIGHT: it is a person talking and it should carry
   across the page. The form gets CONTRAST and a RULE: it is not shouting, it
   is stamped, and a printed line does not raise its voice, it just refuses to
   go away. That difference is the joke the whole design is built on. */
#ui #ui-title .sub{margin:30px 0 0;font-family:var(--hand);font-size:35px;line-height:1.22;
  font-weight:700;color:var(--ink);transform:rotate(-.8deg);max-width:560px;
  /* A soft paper-coloured halo so the hand stays legible where it crosses a
     ruled line — ink on paper sits ON the rule, it does not dodge it. */
  text-shadow:0 1px 0 rgba(255,252,246,.9), 0 0 12px rgba(255,250,242,.7)}
#ui #ui-title .sub em{font-style:normal;color:var(--pink)}
#ui #ui-title .official{margin-top:14px;font:700 12px/1.8 var(--form);letter-spacing:.3em;
  color:#6d6257;display:inline-block;padding:5px 0 5px;
  border-top:1.5px solid rgba(90,80,70,.38);border-bottom:1.5px solid rgba(90,80,70,.38)}
/* THE CONTROLS, AS SMALL PRINT. The PIXI title carried three lines telling the
   player which keys fly the ship, and dropping them to gain a nicer picture
   would have been a straight regression. They belong to the FORM voice, not
   the hand: a printed service form has instructions set small under the
   heading, nobody decorated them, and they are the honest layer showing
   through — which is the whole thesis of this screen. */
#ui #ui-title .smallprint{margin-top:12px;max-width:560px;
  font:600 10px/1.9 var(--form);letter-spacing:.16em;color:var(--print);
  text-transform:uppercase}

#ui #ui-title .menu{position:absolute;left:88px;top:452px;display:flex;flex-direction:column;
  align-items:flex-start;gap:13px}
#ui #ui-title .mrow{display:flex;align-items:center;gap:14px}
#ui #ui-title .mrow:nth-child(2) .sticker{transform:rotate(-1.2deg)}
#ui #ui-title .mrow:nth-child(3) .sticker{transform:rotate(.9deg)}
#ui #ui-title .mrow:nth-child(4) .sticker{transform:rotate(-.6deg)}
/* THE TELL (SCOPE §5.2). A counter, and beside it a note in the same hand that
   decorated everything else — read as pride, written as an inventory. It is
   never remarked on again, here or on the results page where it is 8. */
#ui .scrawl{font-family:var(--hand);font-size:20px;color:var(--print);
  transform:rotate(-2deg);white-space:nowrap}
#ui .scrawl b{color:var(--pink);font-size:23px}
/* The locker-door cluster. Four photographs, overlapping, each at a different
   angle and a different size — a stack that accreted rather than a gallery
   that was laid out. Nothing here is aligned to anything, which is the only
   way a grid of faces stops looking like a grid of faces. */
#ui #ui-title .crew{position:absolute;right:0;top:0;width:720px;height:720px}
#ui #ui-title .crew .polaroid:nth-child(1){right:96px;top:70px;transform:rotate(4.5deg)}
#ui #ui-title .crew .polaroid:nth-child(2){right:250px;top:210px;transform:rotate(-5deg)}
#ui #ui-title .crew .polaroid:nth-child(3){right:60px;top:352px;transform:rotate(-2deg)}
#ui #ui-title .crew .polaroid:nth-child(4){right:394px;top:414px;transform:rotate(6deg)}

/* =========================================================================
   MOTION
   -------------------------------------------------------------------------
   ONE RULE ABOVE THE OTHERS: every keyframe here animates the INDIVIDUAL
   transform properties — `translate`, `rotate`, `scale` — and never
   `transform`. Every hand-placed angle in this design lives in an inline
   `transform:rotate(...)`, and an animation on `transform` would wipe all of
   them the instant it started; the individual properties compose with it, so a
   sticker keeps the crooked angle somebody pressed it on at and bobs around
   THAT.

   WHAT MOVES AND WHY. The decoration moves because it is loose: paper lifts,
   charms hang, tape peels, a sticker is 0.3mm off the page and the page is
   being breathed on.

   NOTHING PULSES IN UNISON. Two things guarantee that, and both are in
   title.js: every object gets a duration drawn from a range, and every object
   gets a NEGATIVE animation-delay, which starts it already part-way through
   its own cycle. Matched periods with staggered starts still beat against each
   other; mismatched periods with staggered starts never resolve. The second is
   the difference between "alive" and "a screensaver".
   ========================================================================= */

/* Amplitudes are small on purpose. 5px and 1.4deg at six seconds is at the
   edge of noticing, which is where idle motion belongs — you should catch it
   in peripheral vision and never once look at it. */
@keyframes ui-bob    {0%,100%{translate:0 0}      50%{translate:0 -5px;rotate:1.4deg}}
@keyframes ui-bobx   {0%,100%{translate:0 0}      50%{translate:3px -3px;rotate:-1.2deg}}
@keyframes ui-peel   {0%,100%{translate:0 0}      50%{translate:0 -1.6px;rotate:-1.1deg}}
@keyframes ui-drift  {0%,100%{rotate:0deg}        50%{rotate:.7deg}}
@keyframes ui-breathe{0%,100%{scale:1}            50%{scale:1.006}}
@keyframes ui-twinkle{0%,100%{scale:1;opacity:.88}50%{scale:1.16;opacity:1}}
@keyframes ui-shift  {0%,100%{opacity:.7}         50%{opacity:1}}
/* A pendulum, not a wobble: the swing keyframes are for things whose
   transform-origin is their hanging point. Eased at the ends because a
   pendulum is slowest where it turns around, and a linear swing is a
   metronome. */
@keyframes ui-swing  {0%,100%{rotate:-8deg}       50%{rotate:8deg}}
@keyframes ui-swingS {0%,100%{rotate:-2.5deg}     50%{rotate:2.5deg}}
/* Full-width trim gets its own keyframe, and it is the only one with no
   rotation in it. A 1280px strip turned by the 0.7deg that looks like nothing
   on a 40px sticker lifts its far end by eight pixels. */
@keyframes ui-trim   {0%,100%{translate:0 0}      50%{translate:3px -1px}}

/* SCREEN TRANSITION — the plate slides and the decoration lags behind it. That
   lag is the entire trick. A panel that slides in with its contents welded to
   it is a panel; a panel whose stickers arrive a beat late is a physical board
   with things stuck to it that have their own inertia. */
#ui .screen.on{animation:ui-screenIn .34s ease both}
@keyframes ui-screenIn{from{opacity:0} to{opacity:1}}
#ui .screen.on > .stage > .plate-slide{
  animation:ui-plateIn .44s cubic-bezier(.18,.86,.24,1.02) both}
@keyframes ui-plateIn{from{translate:64px 0;opacity:.12} to{translate:0 0;opacity:1}}
/* For the length of the entry the loose objects abandon their idle loops and
   fly in instead; --lag is per-element and set in JS, so they do not arrive as
   a sheet either. !important is deliberate — it is overriding the inline
   animation the idle pass wrote, which is the only way to win against it
   without JS having to save and restore every element's animation string. */
#ui .screen.entering .deco,#ui .screen.entering .hw{
  animation-name:ui-lagIn !important;animation-duration:.58s !important;
  animation-delay:var(--lag,.07s) !important;animation-iteration-count:1 !important;
  animation-fill-mode:both !important;
  animation-timing-function:cubic-bezier(.16,.9,.28,1.02) !important}
@keyframes ui-lagIn{from{translate:36px -9px;opacity:0;rotate:-7deg}
                    to  {translate:0 0;opacity:1;rotate:0deg}}

/* ⚠️ THE RULE, WRITTEN AS CODE.
   The instrument does not move and the play field does not move. Not a bob,
   not a breath, not a hover. These exist so a later hand that adds a cheerful
   animation to "everything" cannot reach the cockpit. Delete them and the
   design is gone.

   AMENDED: this used to say "the candy stops at the bezel in the motion layer
   exactly as it stops there in the paint layer". Half of that is no longer
   true — the paint now goes all the way in, because game 1 is children and
   somebody decorated the gunsight too (see src/ui/hud.js). The MOTION still
   stops here, and the split is better for being narrower:

       DECORATED, BUT STILL. An instrument may be pink. It may not bob.

   ⚠️ These rules cannot tell an angle used for MOTION from one used for
   LAYOUT, so anything inside `.comms` that needs a static offset or angle must
   use `transform`, which is not listed here. Writing it the modern way gets it
   silently discarded — that is exactly how the comms panel first laid out from
   its own top-left corner, halfway off the screen. */
#ui .comms,#ui .comms *{animation:none !important;translate:none !important;
                rotate:none !important;scale:none !important;transition:none !important}
#ui .field,#ui .field *{animation:none !important;translate:none !important;
                rotate:none !important;scale:none !important}
/* The roll call is a list of names being read. Names hold still. */
#ui .roll,#ui .roll *{animation:none !important}

/* Paper light. Not the paper moving — the light ON it, on a period long enough
   (17s) that it never syncs with anything that bobs. */
#ui .paper{animation:ui-breathe 11s ease-in-out infinite}
#ui .paper .vig{animation:ui-shift 17s ease-in-out infinite}

/* Hover on the loose furniture too, so the page feels touchable everywhere and
   not only on the things that are buttons. */
#ui .polaroid,#ui .medal,#ui .charm{
  transition:translate .22s var(--bounce),rotate .22s var(--bounce),
             scale .22s var(--bounce)}
#ui .polaroid:hover,#ui .medal:hover{translate:0 -5px;rotate:-1.4deg;scale:1.025;z-index:5}
/* A keyring photo hangs from its ring, not from its middle. */
#ui .charm{transform-origin:top center}
#ui .card.press,#ui .medal.press{scale:1.05 .9;translate:0 3px;transition-duration:.06s}

/* ⚠️ MAXIMALISM IS OPTIONAL.
   Two gates, in this order. A reduce preference turns everything off unless
   motion has been explicitly asked back — which is why the media query tests
   :not([data-motion="on"]) rather than standing alone. The attribute then
   turns it off for anyone, preference or not.

   title.js seeds data-motion from the GAME'S OWN motion setting, which already
   defaults to prefers-reduced-motion (see DEFAULTS in main.js). So a player who
   turned motion off in the pause menu gets a still title screen too, and there
   is exactly one switch rather than two that disagree. */
@media (prefers-reduced-motion:reduce){
  #ui:not([data-motion="on"]) *,
  #ui:not([data-motion="on"]) *::before,
  #ui:not([data-motion="on"]) *::after{
    animation:none !important;transition:none !important}
}
#ui[data-motion="off"] *,
#ui[data-motion="off"] *::before,
#ui[data-motion="off"] *::after{animation:none !important;transition:none !important}

/* ⚠️ THE PORTRAIT BLOCKER WINS.
   main.js draws "TURN YOUR PHONE" on the Pixi stage, which is BELOW this
   layer in the document. Without this rule a portrait phone gets a decorated
   title screen sitting on top of the message telling it to rotate, and the
   message is invisible while its own screen is unusable. */
#ui.rotate-blocked .screen{display:none}

/* ===========================================================================
   THE STICKER SHEET
   ---------------------------------------------------------------------------
   Every path into assets/ lives here and nowhere else. Copied out of
   tools/ui-mock/assets/ into assets/ui/deco/ — nothing references tools/,
   which is a scratch directory and is not shipped.

   Three sets, and they are not interchangeable:
     candy/    — Kenney candy props. Furniture, low opacity, in the margins.
     flat/     — solid-fill icons. Read at small sizes, used as objects.
     sticker/  — the outlined variants of the same icons. Read as die-cut.
   =========================================================================== */
#ui .deco[data-img="candy/canePink"]           {background-image:url(../../assets/ui/deco/candy/canePink.png)}
#ui .deco[data-img="candy/creamPink"]          {background-image:url(../../assets/ui/deco/candy/creamPink.png)}
#ui .deco[data-img="candy/creamVanilla"]       {background-image:url(../../assets/ui/deco/candy/creamVanilla.png)}
#ui .deco[data-img="candy/cherry"]             {background-image:url(../../assets/ui/deco/candy/cherry.png)}
#ui .deco[data-img="candy/wafflePink"]         {background-image:url(../../assets/ui/deco/candy/wafflePink.png)}
#ui .deco[data-img="candy/cookiePink"]         {background-image:url(../../assets/ui/deco/candy/cookiePink.png)}
#ui .deco[data-img="candy/cookieChoco"]        {background-image:url(../../assets/ui/deco/candy/cookieChoco.png)}
#ui .deco[data-img="candy/candyRed"]           {background-image:url(../../assets/ui/deco/candy/candyRed.png)}
#ui .deco[data-img="candy/candyGreen"]         {background-image:url(../../assets/ui/deco/candy/candyGreen.png)}
#ui .deco[data-img="candy/candyYellow"]        {background-image:url(../../assets/ui/deco/candy/candyYellow.png)}
#ui .deco[data-img="candy/heart"]              {background-image:url(../../assets/ui/deco/candy/heart.png)}
#ui .deco[data-img="candy/lollipopGreen"]      {background-image:url(../../assets/ui/deco/candy/lollipopGreen.png)}
#ui .deco[data-img="candy/lollipopFruitYellow"]{background-image:url(../../assets/ui/deco/candy/lollipopFruitYellow.png)}
#ui .deco[data-img="candy/cupCake"]            {background-image:url(../../assets/ui/deco/candy/cupCake.png)}
#ui .deco[data-img="candy/gummyWormGreenHead"] {background-image:url(../../assets/ui/deco/candy/gummyWormGreenHead.png)}
#ui .deco[data-img="candy/gummyWormGreenMid"]  {background-image:url(../../assets/ui/deco/candy/gummyWormGreenMid.png)}

#ui .deco[data-img="flat/star"]        {background-image:url(../../assets/ui/deco/flat/star.png)}
#ui .deco[data-img="flat/stars"]       {background-image:url(../../assets/ui/deco/flat/stars.png)}
#ui .deco[data-img="flat/heart"]       {background-image:url(../../assets/ui/deco/flat/heart.png)}
#ui .deco[data-img="flat/hearts"]      {background-image:url(../../assets/ui/deco/flat/hearts.png)}
#ui .deco[data-img="flat/faceHappy"]   {background-image:url(../../assets/ui/deco/flat/faceHappy.png)}
#ui .deco[data-img="flat/exclamations"]{background-image:url(../../assets/ui/deco/flat/exclamations.png)}
#ui .deco[data-img="flat/idea"]        {background-image:url(../../assets/ui/deco/flat/idea.png)}

#ui .deco[data-img="sticker/star"]  {background-image:url(../../assets/ui/deco/sticker/star.png)}
#ui .deco[data-img="sticker/hearts"]{background-image:url(../../assets/ui/deco/sticker/hearts.png)}
#ui .deco[data-img="sticker/drop"]  {background-image:url(../../assets/ui/deco/sticker/drop.png)}
#ui .deco[data-img="sticker/drops"] {background-image:url(../../assets/ui/deco/sticker/drops.png)}
#ui .deco[data-img="sticker/laugh"] {background-image:url(../../assets/ui/deco/sticker/laugh.png)}
#ui .deco[data-img="sticker/music"] {background-image:url(../../assets/ui/deco/sticker/music.png)}
#ui .deco[data-img="sticker/swirl"] {background-image:url(../../assets/ui/deco/sticker/swirl.png)}

/* =========================================================================
   2 — HANGAR  (the mock's SELECT)
   Nine cards, one detail column. The cards are photographs on a page; the
   selection is a sticker slapped over the chosen one, not a glow — a glow is a
   screen affordance and this is not a screen.
   ========================================================================= */
#ui #ui-hangar .head{position:absolute;left:44px;top:26px}
#ui #ui-hangar h2{margin:0;font-family:var(--hand);font-size:52px;color:var(--pink);
  transform:rotate(-1.4deg)}
/* ⚠️ SLIMMER AND TALLER, and the width is the number that moved.
   600px over three columns gave a 188px card holding a 126px-high window —
   landscape, which is the wrong shape for a standing figure and is why every
   chibi was cropped at the shins to fit. 540 gives a 168px card, and the
   window grows to 176: portrait, and taller than it is wide, which is the
   shape a photograph of a person standing up actually is. The grid keeps its
   left edge and its gutter to the detail sheet; only the cards got narrower. */
#ui #ui-hangar .grid{position:absolute;left:44px;top:112px;width:540px;
  display:grid;grid-template-columns:repeat(3,1fr);gap:16px 18px}
/* A real <button>, so a keyboard reaches it and a screen reader names it. The
   resets are the whole cost of that. */
#ui .card{position:relative;background:#fffdfa;padding:8px 8px 0;cursor:pointer;
  box-shadow:0 3px 9px #00000024;border-radius:7px;border:0;font:inherit;
  -webkit-appearance:none;appearance:none;display:block;width:100%;
  transition:translate .12s var(--bounce),rotate .12s var(--bounce),scale .12s var(--bounce)}
/* White, for the same reason the polaroid well is white — see the note there.
   The chibis are full-colour art and were sitting in nine dark holes. */
#ui .card .win{height:148px;background:#fff;overflow:hidden;position:relative;border-radius:6px;
  display:flex;align-items:flex-end;justify-content:center;
  box-shadow:inset 0 0 0 1px #e8dcd0,inset 0 2px 6px #b9a89844}
#ui .card .win::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(74% 56% at 50% 104%,#ffd9ea7a,transparent 72%)}
/* ⚠️ THE FIGURE MUST FIT. It used to be 150px tall inside a 126px window with
   a -14px bottom margin, i.e. 38px of girl deliberately hidden below the frame
   — which is what cropped every one of them at the shins. 154 inside 176 with
   the margin at zero leaves 22px of headroom and puts her feet on the floor of
   the frame. `align-items:flex-end` does the standing; nothing is hidden.

   Do not reintroduce a negative margin here to make her look bigger. The way
   to make her bigger is a taller window, because a window is a crop and a
   crop of a person is a person with their feet cut off. */
#ui .card .win img{height:130px;margin-bottom:0}
#ui .card .nm{font:700 11px/2.3 var(--form);letter-spacing:.14em;text-align:center;
  color:var(--print)}
#ui .card .chip{position:absolute;left:8px;top:8px;width:11px;height:11px;
  border-radius:50%;border:2px solid #fff;box-shadow:0 1px 2px #0004;z-index:5}
/* Each photo is stuck down at its own angle. A perfect 3x3 of perfect
   rectangles is a database view; a degree and a half of scatter is a page. The
   values are hand-picked rather than random so the layout is stable between
   visits — a screen that reshuffles cannot be reviewed twice. */
#ui .card:nth-child(1){transform:rotate(-1.1deg)} #ui .card:nth-child(2){transform:rotate(.8deg)}
#ui .card:nth-child(3){transform:rotate(1.4deg)}  #ui .card:nth-child(4){transform:rotate(.6deg)}
#ui .card:nth-child(5){transform:rotate(-1.3deg)} #ui .card:nth-child(6){transform:rotate(1deg)}
#ui .card:nth-child(7){transform:rotate(1.2deg)}  #ui .card:nth-child(8){transform:rotate(-.7deg)}
#ui .card:nth-child(9){transform:rotate(-1.5deg)}
/* Hover and selection are written as the INDIVIDUAL properties, never as
   `transform`, which would quietly wipe the crooked angle above — same
   specificity, later rule wins, and every card would snap square the moment you
   touched it. These compose with it instead, so a card lifts and tilts a
   further degree from wherever somebody stuck it down. */
#ui .card:hover{translate:0 -6px;rotate:-1.2deg;scale:1.04;z-index:3}
#ui .card:focus-visible{outline:3px solid var(--pink);outline-offset:3px;
  translate:0 -6px;rotate:-1.2deg;scale:1.04;z-index:4}
#ui .card.sel{translate:0 -7px;rotate:-1.8deg;scale:1.03;z-index:2;
  box-shadow:0 8px 18px #0000003a,0 0 0 5px var(--pink)}
#ui .card.sel .nm{color:var(--pink)}
/* Selection is a physical act: a heart sticker AND a bow, both added on top of
   the photograph, both slightly off-register. A glow would be a screen
   affordance, and this is not a screen. */
#ui .card .knot{position:absolute;left:-13px;bottom:16px;--w:38px;display:none;z-index:4}
#ui .card.sel .knot{display:block}
#ui .card .pick{position:absolute;right:-14px;top:-14px;display:none;z-index:4;
  filter:drop-shadow(0 2px 3px rgba(80,40,60,.35))}
#ui .card.sel .pick{display:block}

#ui #ui-hangar .detail{position:absolute;left:684px;top:60px;width:556px;height:604px}
#ui #ui-hangar .detail .sheet{position:absolute;inset:0;background:#fffdf9;
  box-shadow:0 6px 22px #00000026;transform:rotate(1.1deg);border-radius:3px}
#ui #ui-hangar .detail .body{position:absolute;inset:0;padding:30px 34px}
#ui #ui-hangar .big{position:absolute;right:22px;bottom:0;width:236px;height:452px;
  background:#050c08;overflow:hidden;display:flex;align-items:flex-end;
  /* No border-radius here on purpose. This element is `.big.crt`, and its glass
     radius belongs to `.crt` — stating it in both places means the more
     specific one silently wins and the CRT rule looks broken. */
  justify-content:center}
#ui #ui-hangar .big img{height:452px;position:absolute;bottom:0}
/* 244px, not 290: the text column has to stop before the photograph starts, and
   the photograph overhangs the sheet's right edge on purpose. */
#ui .who{position:relative;z-index:2;width:244px}
/* ⚠️ EVERY HANDWRITTEN SIZE ON THIS COLUMN IS MULTIPLIED BY `--handScale`.
   The nine faces were not drawn to one another — at a flat 56px, Sacramento
   sets tiny and Permanent Marker sets huge — so each pilot carries a
   correction (see THE NINE HANDS at the top of this file) and the column
   occupies the same space whoever is selected. Without this, stepping through
   the roster with the arrows makes the whole detail sheet jump. */
#ui .who .cs{font-family:var(--hand);font-size:calc(44px * var(--handScale));
  color:var(--pink);line-height:.9;margin:0}
#ui .who .real{font:700 13px/1.6 var(--form);letter-spacing:.13em;color:var(--print)}
/* Her sign, printed like a form field with the glyph as the one warm mark.
   Sits directly under the real name because a sign belongs with an identity,
   not with the statistics — it is who she is, not how she flies. */
#ui .who .sign{margin-top:7px;display:flex;align-items:center;gap:8px}
#ui .who .sign .gl{font-size:21px;line-height:1;color:var(--pink);
  text-shadow:0 1px 0 #fff,0 2px 3px #0002}
#ui .who .line{margin-top:13px;font-family:var(--hand);
  font-size:calc(20px * var(--handScale));color:var(--ink);line-height:1.26}
#ui .who .paint{margin-top:9px;display:flex;align-items:center;gap:10px}
#ui .who .paint .dot{width:26px;height:26px;border-radius:50%;flex:none;
  border:3px solid #fff;box-shadow:0 2px 4px #0003}
/* HER OWN WORDS, verbatim out of src/pilots.js. SCOPE §6 names the danger that
   candy flattens the writing into a mascot; the cheapest insurance is to print
   the writing ON the candy. */
#ui .who .say{margin-top:9px;font-family:var(--hand);
  font-size:calc(19px * var(--handScale));line-height:1.22;color:var(--pink)}

/* --- her own answers -----------------------------------------------------
   ⚠️ PIPS, NOT BARS, AND THE DIFFERENCE IS THE ARGUMENT.

   A continuous fill bar is an instrument: it implies a measured quantity with
   a scale behind it. There is no such quantity — `accel` and `maxSpeed` are
   theme-wide and every pilot flies identically (src/logsheet.js says this at
   length). Five discs, four of them filled in, is what a person does to a
   printed form, and it claims exactly as much as it can support.

   The labels stay in the form's printed voice and the pips are the answer, so
   the row reads the same way STATUS · ready!! does. */
#ui .who .statsheet{margin-top:9px;padding:7px 10px 6px;border-radius:8px;
  background:#fff8f1cc;box-shadow:inset 0 0 0 1px #eadfd2,0 1px 0 #fff;
  transform:rotate(-.5deg)}
#ui .who .statsheet .hdr{display:block;margin-bottom:4px;color:var(--print)}
#ui .who .stat{display:flex;justify-content:space-between;align-items:center;
  padding:1px 0}
#ui .who .stat + .stat{border-top:1px dashed var(--rule)}
#ui .who .pips{display:flex;gap:4px;flex:none}
/* An empty pip is the printed circle; a filled one is ink in it. The filled
   ones are pink and very slightly larger, because a child filling in a box
   overshoots it, and a perfectly inscribed dot reads as a rendered widget. */
#ui .who .pips i{width:10px;height:10px;border-radius:50%;
  box-shadow:inset 0 0 0 1.5px #d9c9ba}
#ui .who .pips i.on{background:var(--pink);box-shadow:inset 0 0 0 1.5px #ffffff80;
  scale:1.14}
/* What she wrote under the boxes when the boxes were not enough. In her hand,
   in her paint colour's neighbourhood, and allowed to be a boast. */
#ui .who .brag{margin-top:4px;font-family:var(--hand);
  font-size:calc(14px * var(--handScale));line-height:1.18;color:var(--ink);
  opacity:.85}
#ui .who .rows{margin-top:8px;border-top:1px dashed var(--rule);padding-top:6px}
#ui .who .rows div{display:flex;justify-content:space-between;align-items:center;
  padding:2px 0;border-bottom:1px dashed var(--rule)}
#ui .who .rows b{font-family:var(--hand);font-size:calc(19px * var(--handScale));
  color:var(--ink);font-weight:400}
#ui .who .rows b.ok{color:var(--pink)}
/* The hull she actually flies, printed into the form beside the word AIRFRAME.
   The customiser is gone (see hangar.js) so this is the only place the SHIP is
   visible before launch, and a pilot-select screen that never shows the
   aircraft is a casting call. */
#ui .who .rows img.hull{height:40px;width:auto;image-rendering:pixelated;
  filter:drop-shadow(0 2px 2px rgba(80,50,60,.3))}
#ui #ui-hangar .go{position:absolute;left:34px;bottom:34px;z-index:3;
  display:flex;align-items:center;gap:12px}

/* THE CYCLING ARROWS. Kept from the Pixi hangar because nine of anything wants
   a next and a previous. Drawn as paper tabs rather than as chevrons in a
   circle: a round grey button with an angle bracket in it is a widget, and
   nothing else on this page is a widget. */
#ui .arrow{position:absolute;top:236px;z-index:6;width:34px;height:52px;
  border:4px solid #fff;border-radius:8px;background:var(--paper);cursor:pointer;
  font:700 24px/1 var(--form);color:var(--print);
  box-shadow:0 3px 0 #e0cfc0,0 5px 9px #00000026;
  transition:translate .16s var(--bounce),scale .16s var(--bounce)}
/* Sited ON the viewer's two edges, not beside it. Beside it they sat on the
   last thirty pixels of her quotation, which is the one piece of writing SCOPE
   §6 says must survive the candy — and navigation for a picture belongs on the
   picture anyway. 224 and 22 are the viewer's own inset numbers. */
#ui .arrow.prev{right:224px} #ui .arrow.next{right:22px}
#ui .arrow:hover{translate:0 -3px;scale:1.06;color:var(--pink)}
#ui .arrow:focus-visible{outline:3px solid var(--pink);outline-offset:3px}
#ui .arrow:active{translate:0 3px;scale:1.06 .9;box-shadow:0 1px 0 #e0cfc0}

/* -------------------------------------------------------------------------
   THE CRT VIEWER
   -------------------------------------------------------------------------
   src/render/crt.js is a WebGL fragment shader and cannot come across, but its
   numbers can, and its opening note is the brief: "deliberately heavy — subtle
   would be worse than none".

   FIVE OF ITS SEVEN EFFECTS SURVIVED, at the shader's own parameters:
     scanlines   0.80 + 0.20*sin(y * 1.047)    -> a 6px repeating gradient at 20%
     vignette    1 - 0.30 * r^2                -> a radial-gradient at 30%
     bloom       col += col*col * 0.55         -> a blurred, screen-blended copy
     flicker     0.025*sin(11t) + 0.012*sin(37t) -> a two-rate brightness loop
     dither      ordered 4x4 Bayer             -> the same 4x4 matrix, as an SVG
                                                  tile in overlay blend
   TWO DID NOT, and there is no CSS that does them honestly:
     BARREL DISTORTION (0.035 * r^2 sample warp) needs a per-pixel resample.
     RADIAL CHROMATIC ABERRATION. A flat sideways offset is available and the
       shader explicitly rejects it — "a fixed sideways offset is a uniform
       smear and reads as a mistake" — so a wrong version is worse than none.
       On green-on-black art it buys almost nothing anyway.
   ------------------------------------------------------------------------- */
/* Rounded, and that reads as MORE of an instrument rather than less. The mock's
   argument for putting a screen on a paper page is that "a screen showing a
   person is a screen"; every CRT anyone pictures has a radiused glass, so a
   hard 90-degree corner was the one detail saying "div". */
#ui .crt{position:relative;overflow:hidden;background:#050c08;border-radius:10px;
  box-shadow:0 0 0 1px #22201d inset,0 0 26px #45c77e26 inset;
  animation:ui-crtflicker 1.7s steps(1,end) infinite}
#ui .crt > img{position:absolute;bottom:0}
/* The phosphor's light, given back before the dither quantises it. */
#ui .crt > img.bloom{filter:blur(7px) brightness(1.5) saturate(1.2);
  mix-blend-mode:screen;opacity:.55;pointer-events:none}
/* ⚠️ THE BLOOM IS TUNED TO THE ART, and the two ages are not the same art.
   The numbers above are the shader's, and the shader was written for the adult
   pinups: sparse green line work on black, where `col + col*col*0.55` reads as
   a phosphor giving its light back. The chibi set is dense, fully opaque and
   pale, so the same screen blend lays a 55% white haze over the whole figure —
   it turned Wake's blue flightsuit near-white and made the hero viewer the
   worst-looking render of a pilot on a screen otherwise full of crisp
   thumbnails. Same effect, a third of the dose. */
#ui .crt.crt-young > img.bloom{filter:blur(5px) brightness(1.12) saturate(1.05);
  opacity:.20}
#ui .crt .lines{position:absolute;inset:0;pointer-events:none;z-index:3;
  background:repeating-linear-gradient(to bottom,
    rgba(0,0,0,.20) 0 3px, rgba(0,0,0,0) 3px 6px)}
#ui .crt .dither{position:absolute;inset:0;pointer-events:none;z-index:4;
  opacity:.22;mix-blend-mode:overlay;background-size:4px 4px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' shape-rendering='crispEdges'%3E%3Cg fill='%23ffffff'%3E%3Crect x='0' y='0' width='1' height='1' opacity='.06'/%3E%3Crect x='2' y='0' width='1' height='1' opacity='.44'/%3E%3Crect x='1' y='1' width='1' height='1' opacity='.69'/%3E%3Crect x='3' y='1' width='1' height='1' opacity='.19'/%3E%3Crect x='1' y='2' width='1' height='1' opacity='.56'/%3E%3Crect x='3' y='2' width='1' height='1' opacity='.31'/%3E%3Crect x='0' y='3' width='1' height='1' opacity='.81'/%3E%3Crect x='2' y='3' width='1' height='1' opacity='.94'/%3E%3C/g%3E%3C/svg%3E")}
#ui .crt .vig{position:absolute;inset:0;pointer-events:none;z-index:5;
  background:radial-gradient(70% 62% at 50% 50%,transparent 38%,rgba(0,0,0,.30) 100%)}
/* Two rates that never line up, exactly as the shader's two sines do not. */
@keyframes ui-crtflicker{
  0%{filter:brightness(1.000)} 14%{filter:brightness(1.024)}
  29%{filter:brightness(0.988)} 43%{filter:brightness(1.011)}
  57%{filter:brightness(0.996)} 71%{filter:brightness(1.031)}
  86%{filter:brightness(0.982)} 100%{filter:brightness(1.000)}}

/* =========================================================================
   4 — RESULTS / ROLL CALL
   The screen the whole idea is for. A scrapbook page made after a mission: a
   taped-in header, a hand-ruled roll call, a sticker awarded per name. Every
   outcome gets a warm word and a gold star, INCLUDING the ones that are not
   returns. The chrome is not lying — it simply has one register and uses it for
   everything. That is the horror and it costs nothing.

   THE TEST THIS SCREEN HAS TO PASS. Everything decorative is OUTSIDE a hard
   rectangle: x 78-710, y 162-640, the nine rows. Not one clip, bead, bow,
   charm, pompom or sticker enters it, and the MOTION block freezes everything
   inside `.roll` besides. Loud on all four margins, silent across the names. If
   a later hand puts a sticker on a name, the design is over.
   ========================================================================= */
#ui #ui-results .sheet{position:absolute;left:44px;top:26px;width:700px;height:668px;
  background:#fffdf8;box-shadow:0 8px 26px #00000026;transform:rotate(-.5deg);
  border-radius:3px}
#ui #ui-results h2{position:absolute;left:76px;top:44px;margin:0;font-family:var(--hand);
  font-size:60px;color:var(--pink);transform:rotate(-1.8deg);line-height:.9;
  white-space:nowrap}
#ui #ui-results .date{position:absolute;left:82px;top:126px;font:700 10px/1 var(--form);
  letter-spacing:.22em;color:var(--print)}
#ui #ui-results .roll{position:absolute;left:78px;top:162px;width:632px}
#ui .rrow{display:grid;grid-template-columns:44px 118px 1fr 168px 36px;align-items:center;
  gap:10px;height:53px;border-bottom:1px dashed var(--rule)}
#ui .rrow .mug{width:38px;height:38px;border-radius:50%;overflow:hidden;position:relative;
  background:#191324;border:3px solid #fff;box-shadow:0 1px 3px #0003;display:block}
#ui .rrow .cs{font-family:var(--hand);font-size:25px;color:var(--ink);line-height:1}
#ui .rrow .real{font:600 11px/1.5 var(--form);letter-spacing:.1em;color:var(--print)}
/* The outcome word. Two states, ONE VOICE. `home` and `stayed` differ by hue
   only — never by weight, never by an icon that means "bad". There is no red on
   this page and there is no cross. */
#ui .rrow .out{font:700 12px/1 var(--form);letter-spacing:.15em;padding:7px 12px;
  border-radius:999px;text-align:center;border:3px solid #fff}
#ui .rrow .out.home{background:var(--pink-pale);color:#d5417f;box-shadow:0 2px 0 #f4cfe0}
#ui .rrow .out.stayed{background:#f0ece6;color:#8d8279;box-shadow:0 2px 0 #ddd6cd}
#ui .rrow .st{text-align:right}
#ui .rrow .st .deco{position:relative;display:inline-block;
  filter:drop-shadow(0 1px 2px rgba(80,50,60,.3))}

#ui #ui-results .side{position:absolute;left:772px;top:26px;width:466px;height:668px}
#ui #ui-results .medals{position:absolute;left:14px;top:34px;width:436px}
#ui #ui-results .medals .t{font-family:var(--hand);font-size:34px;color:var(--pink);
  transform:rotate(-1.2deg);margin-bottom:14px}
#ui #ui-results .medals .none{font-family:var(--hand);font-size:21px;color:var(--print);
  transform:rotate(-1deg);line-height:1.4}
#ui .medal{position:relative;display:flex;align-items:center;gap:12px;background:#fffdf8;
  padding:11px 16px;border-radius:14px;margin-bottom:11px;
  box-shadow:0 3px 9px #00000022;border:4px solid #fff}
#ui .medal:nth-child(3){transform:rotate(-1deg)} #ui .medal:nth-child(5){transform:rotate(.8deg)}
#ui .medal .deco{position:relative;flex:none}
#ui .medal .n{font:700 13px/1.2 var(--form);letter-spacing:.1em;color:var(--ink)}
#ui .medal .h{font-family:var(--hand);font-size:15px;color:var(--print)}
#ui #ui-results .tot{position:absolute;left:26px;bottom:126px}
#ui #ui-results .tot .k{font:700 10px/1 var(--form);letter-spacing:.24em;color:var(--print)}
#ui #ui-results .tot .v{font-family:var(--hand);font-size:66px;color:var(--ink);line-height:.9}
#ui #ui-results .btns{position:absolute;left:26px;bottom:36px;display:flex;gap:12px;
  align-items:center}
/* THE SAME COUNTER AS THE TITLE SCREEN, in the same happy hand, with no
   acknowledgement anywhere on the page. SCOPE-facade.md 5.2. */
#ui #ui-results .count{position:absolute;left:82px;top:654px;font-family:var(--hand);
  font-size:19px;color:var(--print);transform:rotate(-1.6deg)}
#ui #ui-results .count b{color:var(--pink);font-size:23px}

/* =========================================================================
   5 — PAUSE
   A card dropped onto the page mid-mission. It sits over the REAL game, which
   is still on the canvas underneath and still lit — a pause screen that
   replaces the game forgets what the player is looking at.
   ========================================================================= */
/* Dim, do not black out. The player must still see the corridor she is standing
   in. The dim sits under the DOM card and over the canvases, so the game
   darkens and the decoration does not: the interface has no idea anything has
   stopped, which is the same joke as the roll call told in one rule. */
#ui .screen .dim{position:absolute;inset:0;background:#0b0e1899;
  backdrop-filter:blur(2px)}
#ui .cardscreen .card{position:absolute;left:50%;top:50%;width:470px;
  transform:translate(-50%,-50%) rotate(-1.6deg);background:var(--paper);
  padding:44px 40px 36px;border-radius:4px;box-shadow:0 22px 50px #000000a6}
#ui .cardscreen .card .grain{position:absolute;inset:0;opacity:.45;border-radius:4px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.3'/%3E%3C/svg%3E");
  mix-blend-mode:multiply;pointer-events:none}
#ui .cardscreen h2{margin:0 0 4px;font-family:var(--hand);font-size:56px;color:var(--pink);
  text-align:center;line-height:.9;position:relative;white-space:nowrap}
#ui .cardscreen .sub{text-align:center;font-family:var(--hand);font-size:19px;color:var(--print);
  margin-bottom:22px;position:relative;line-height:1.45}
#ui .cardscreen .list{position:relative;display:flex;flex-direction:column;gap:12px;
  align-items:stretch}
#ui .cardscreen .list .sticker{justify-content:center;width:100%;text-align:center}
#ui .cardscreen .list .sticker:nth-child(2){transform:rotate(.7deg)}
#ui .cardscreen .list .sticker:nth-child(3){transform:rotate(-.7deg)}
#ui .cardscreen .hint{position:relative;margin-top:16px;text-align:center;
  font:600 10px/1 var(--form);letter-spacing:.22em;color:var(--print)}
/* A ribbon banner, pure CSS: a bar with two notched tails. */
#ui .cardscreen .ribbon{position:absolute;left:50%;top:-26px;transform:translateX(-50%);
  background:var(--pink);color:#fff;font:700 12px/1 var(--form);letter-spacing:.24em;
  padding:11px 34px;box-shadow:0 4px 10px #00000040;
  clip-path:polygon(0 0,100% 0,100% 100%,50% 76%,0 100%)}

/* ---------------------------------------------------------------------------
   THE CARD SCREENS — pause, options, confirm.

   One block, three screens. They were three when the pause card was the only
   one and its rules were scoped to `#ui-pause`; the moment OPTIONS and the
   abandon confirm came across as DOM, that scoping would have meant three
   copies of a card, which is how the second one quietly stops matching the
   first. `.cardscreen` is added by each screen module.

   Two widths beyond the default, and only two, because a card that is exactly
   as wide as its content is a card that changes shape every time the content
   does.
--------------------------------------------------------------------------- */
#ui .cardscreen .card.wide{width:600px}
#ui .cardscreen .card.narrow{width:430px}

/* ---------------------------------------------------------------------------
   THE SETTINGS ROWS.

   ⚠️ These are REAL `<input type=range>` and a real `role=switch` button
   wearing paper clothes. Every rule below is appearance; not one of them
   touches behaviour. Drag, keyboard, hit slop, focus ring and the accessibility
   tree all come from the elements themselves, which is more than the Pixi
   widgets had and is the whole reason the port was worth doing.
--------------------------------------------------------------------------- */
#ui .cardscreen .orows{position:relative;display:flex;flex-direction:column;
  gap:14px;margin:6px 0 24px}
#ui .cardscreen .orow{display:grid;grid-template-columns:106px 1fr 26px;
  align-items:center;gap:14px}
/* Every other row sits a degree off, so four rows read as four things somebody
   wrote down rather than as a table. */
#ui .cardscreen .orow:nth-child(even){transform:rotate(.5deg)}
#ui .cardscreen .orow:nth-child(odd){transform:rotate(-.4deg)}
#ui .cardscreen .oname{font:700 11px/1 var(--form);letter-spacing:.2em;
  color:var(--print)}
#ui .cardscreen .octl{display:flex;align-items:center;gap:10px;min-height:44px}
#ui .cardscreen .ochm{font-size:17px;color:var(--c);text-align:center;opacity:.85}

/* The slider: a strip of tape with a bead on it. The TRACK is 44 tall and
   transparent above and below the visible strip -- the strip reads as 12px and
   the finger target is the full row, which is the trick a drawn slider cannot
   do and a real input gets for free. */
#ui .cardscreen .slid{-webkit-appearance:none;appearance:none;flex:1;
  height:44px;background:transparent;cursor:pointer;margin:0}
#ui .cardscreen .slid::-webkit-slider-runnable-track{height:12px;border-radius:8px;
  background:linear-gradient(90deg,var(--c) 0 var(--f,50%),#e6ddd4 var(--f,50%) 100%);
  box-shadow:inset 0 1px 2px #0000001f}
#ui .cardscreen .slid::-moz-range-track{height:12px;border-radius:8px;background:#e6ddd4}
#ui .cardscreen .slid::-moz-range-progress{height:12px;border-radius:8px;background:var(--c)}
#ui .cardscreen .slid::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;
  width:26px;height:26px;margin-top:-7px;border-radius:50%;background:#fffdfa;
  border:3px solid var(--c);box-shadow:0 3px 7px #00000038;transition:scale .12s}
#ui .cardscreen .slid::-moz-range-thumb{width:26px;height:26px;border-radius:50%;
  background:#fffdfa;border:3px solid var(--c);box-shadow:0 3px 7px #00000038}
#ui .cardscreen .slid:active::-webkit-slider-thumb{scale:1.18}
#ui .cardscreen .slid:focus-visible{outline:3px solid var(--pink);outline-offset:4px;
  border-radius:8px}
#ui .cardscreen .pct{min-width:34px;text-align:right;font:700 13px/1 var(--form);
  letter-spacing:.06em;color:var(--print);font-variant-numeric:tabular-nums}

/* The switch: a bead that slides along a short piece of tape, with the state
   spelled out beside it in words. A coloured pill alone is a coin toss -- the
   whole reason MUTE gets to say QUIET or SOUND ON is that a player must never
   have to work out which way "on" points. */
#ui .cardscreen .swtch{-webkit-appearance:none;appearance:none;display:flex;
  align-items:center;gap:12px;background:none;border:0;padding:0;min-height:44px;
  cursor:pointer;font:inherit;color:inherit}
#ui .cardscreen .swtch .knob{width:52px;height:24px;border-radius:14px;
  background:#e6ddd4;box-shadow:inset 0 1px 2px #0000001f;position:relative;
  transition:background .16s;flex:0 0 auto}
#ui .cardscreen .swtch .knob::after{content:"";position:absolute;left:3px;top:3px;
  width:18px;height:18px;border-radius:50%;background:#fffdfa;
  box-shadow:0 2px 5px #00000038;transition:translate .16s}
#ui .cardscreen .swtch[data-on="1"] .knob{background:var(--c)}
#ui .cardscreen .swtch[data-on="1"] .knob::after{translate:28px 0}
#ui .cardscreen .swtch .say{font:700 11px/1 var(--form);letter-spacing:.16em;
  color:var(--print);white-space:nowrap}
#ui .cardscreen .swtch:focus-visible{outline:3px solid var(--pink);outline-offset:4px;
  border-radius:6px}

/* THE PRINTED STAMP on the abandon card. Deliberately identical to the one
   under the results heading: same grey, same tracking, same refusal to raise
   its voice. It is the only thing on that card that acknowledges what is about
   to happen, and it is small. */
#ui .cardscreen .stamp{position:relative;text-align:center;margin:2px 0 24px;
  font:600 10px/1.7 var(--form);letter-spacing:.2em;color:var(--print);opacity:.9}

/* ---------------------------------------------------------------------------
   TURN YOUR PHONE.

   Opaque, top of the stack, and still. See src/ui/rotate.js for why it is not
   a screen and why nothing on it is given an idle period.
--------------------------------------------------------------------------- */
#ui .rotate{position:absolute;inset:0;z-index:40;display:none;
  background:var(--paper);pointer-events:auto}
#ui .rotate.on{display:grid;place-items:center}
#ui .rotate .rot-inner{text-align:center;padding:24px;max-width:min(86vw,460px)}
#ui .rotate h2{margin:18px 0 10px;font-family:var(--hand);font-size:clamp(34px,9vw,58px);
  color:var(--pink);line-height:.95}
#ui .rotate .rot-print{font:600 clamp(9px,2.4vw,11px)/1.9 var(--form);letter-spacing:.2em;
  color:var(--print)}
/* The phone, drawn lying down. A rounded rect on its side with a speaker slot;
   no image, because a 46x78 PNG of a phone is a 46x78 PNG of a phone. */
#ui .rotate .rot-phone{width:clamp(78px,20vw,116px);height:clamp(46px,12vw,68px);
  margin:0 auto;border:4px solid var(--print);border-radius:11px;position:relative;
  background:#fffdfa;box-shadow:0 6px 16px #0000001f;rotate:-8deg}
#ui .rotate .rot-phone i{position:absolute;right:7px;top:50%;translate:0 -50%;
  width:4px;height:26%;border-radius:2px;background:var(--print);opacity:.55}
#ui .rotate .rot-deco{margin-top:16px;display:flex;gap:14px;justify-content:center}
#ui .rotate .rot-star{font-size:18px;color:var(--lilac)}
#ui .rotate .rot-star:nth-child(2){color:var(--pink)}
#ui .rotate .rot-star:nth-child(3){color:var(--lemon)}

/* ---------------------------------------------------------------------------
   .scrolls — WHAT A CARD DOES WHEN THE FLOOR AND THE SHEET DISAGREE.

   The stage is a fixed 1280x720 composition contain-fitted into the window, so
   on a short landscape phone every control on it is scaled DOWN. UI-RESEARCH §1
   settled what to do about that and the sentence is unambiguous: "refuse to go
   below 44 — below that the layout scrolls instead of shrinking." Three card
   screens then shrank anyway, because each of them capped its own scale at
   whatever still fitted in 720 units. Measured on a 750x342 phone, the options
   rows came out 22px against a floor of 44.

   So when `floorScale` reports that honouring the floor no longer fits, the
   card LEAVES THE STAGE. It stops being a scaled composition and becomes an
   ordinary block in ordinary CSS pixels — which is the one arrangement where a
   44px control is 44px, with no arithmetic to get wrong. The screen scrolls.

   The paper and the dim stay exactly where they are: they are full-bleed
   substrate, they have no composition to preserve, and the sheet must still
   reach every corner or the card is floating on black.

   ⚠️ `scale:none` on the card is load-bearing. `floorScale` wrote a scale onto
   it on the pass before this class went on, and a stale 1.8 would multiply a
   card that is now already the right size. -------------------------------- */
#ui .cardscreen.scrolls{overflow-y:auto;-webkit-overflow-scrolling:touch}
#ui .cardscreen.scrolls .stage{position:static;width:auto;height:auto;
  translate:none;scale:none;overflow:visible}
#ui .cardscreen.scrolls .card{position:relative;left:auto;top:auto;scale:none;
  transform:rotate(-1.6deg);margin:26px auto;
  max-width:calc(100vw - 40px)}
/* The hardware that hangs off the card's edges is decoration, and decoration
   that forces a horizontal scrollbar is a bug. Nothing here is load-bearing:
   the composition already expects these to be cropped by the stage. */
#ui .cardscreen.scrolls{overflow-x:hidden}

/* ---------------------------------------------------------------------------
   SHORT AND WIDE — the phone the game actually asks you to hold.

   Scrolling is the correct FALLBACK and it is a poor answer for the options
   card specifically: four rows stacked at real size are ~560px tall, a
   750x342 landscape phone has 342, and a settings card whose DONE button is
   always one drag away is a settings card people give up on.

   The rows are four independent controls with no reading order between them,
   which is exactly the content that survives being put in two columns. Two
   columns halves the height and the card fits without a single control going
   under the floor. This is the same landscape two-column reasoning
   UI-RESEARCH §2 records for the title's buttons.

   Height, not width, is the query. A short window is the constraint whatever
   its width, and `max-height` says that directly instead of inferring it from
   a device guess. -------------------------------------------------------- */
@media (max-height: 620px) and (min-width: 600px){
  #ui .cardscreen.scrolls .card{margin:12px auto}
  #ui .cardscreen.scrolls .card.wide{width:min(760px, 100vw - 32px)}
  #ui .cardscreen.scrolls .orows{display:grid;grid-template-columns:1fr 1fr;
    gap:6px 30px}
  /* The hand loses least by being smaller; the controls lose everything, so
     the heading is where the height comes from. */
  #ui .cardscreen.scrolls h2{font-size:38px}
  #ui .cardscreen.scrolls .sub{margin-bottom:12px;font-size:16px}
  #ui .cardscreen.scrolls .card{padding:26px 34px 22px}
}
