/* ⛔ THE @import THAT USED TO BE HERE COST A WHOLE ROUND TRIP IN FRONT OF FIRST PAINT (UI audit
   [34], measured 336 ms). An @import is SERIAL: the browser cannot even discover fonts/faces.css
   until app.css has arrived and parsed. It is now a <link> in index.html, immediately before this
   sheet, so the two are fetched in PARALLEL. ⚠️ Order still matters — faces.css declares the
   @font-face rules this file references — and a <link> above preserves it exactly.
   ⭐ The font FILES were already preloaded; that never helped, because the @font-face rules
   pointing at them were behind the serial import. */

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   Aggregatoor — bench instrument

   Anodised gunmetal carrying a real brushed grain · bone keycaps · charcoal silkscreen ·
   one bone-white screen for LIVE MEASURED DATA · one blood-red commit key.
   Matte throughout: no gloss, no bevel costume, no glass.

   ⛔ TWO STRUCTURAL RULES THIS FILE LEARNED THE HARD WAY:
   1. EVERY MEDIA QUERY LIVES AT THE END. They sat above the components they override, and at
      equal specificity the later rule wins — so each component added afterwards silently beat
      the phone layout and it collapsed with nothing erroring.
   2. THE READOUT COLOUR IS NOT A HIGHLIGHT. It means "this figure is live and measured". When it
      also carried focus rings, a selected detent and a token symbol, it stopped meaning anything.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

:root{
  /* the bench the instrument sits on */
  --bench:#0E0F10;
  --bench-edge:#000;

  /* the chassis */
  --chassis:#2B2E31;
  --chassis-hi:#35383C;      /* the lit top face of an extrusion */
  --chassis-lo:#212427;      /* a milled recess */
  --chassis-well:#191B1D;    /* a deep well: the screen, the board */
  --hairline:#3E4247;        /* a machined seam */
  --hairline-soft:#33363A;

  /* silkscreen legends printed into the metal.
     --legend-3 was #7E848A: 3.61:1 on the chassis, under the floor, and it was carrying
     "gas unread" and "no fee taken" — decision content, not decoration. Now 5.23:1. */
  --legend:#EDECE8;
  --legend-2:#B3B8BD;
  --legend-3:#9AA1A8;

  /* keycaps: bone and putty, dye-sub charcoal legends */
  --cap:#C8C4BA;
  --cap-hi:#D6D2C9;
  --cap-lo:#A9A59B;
  --cap-ink:#232527;
  --cap-dark:#313437;        /* the same key, unlit */

  /* the instrument screen — LIVE MEASURED DATA ONLY. Bone-white, not amber: luminance carries
     the emphasis so the page has exactly ONE chromatic accent, and a winning number is never
     shown in a red family, which on a trading board reads as a loss. */
  --well:#121110;
  --live:#F3F1EC;            /* 16.7:1 in the well */
  --live-2:#9AA1A8;          /* its labels — 7.2:1 */
  --live-glow:rgba(243,241,236,.16);

  /* ⭐⭐ GOLD — THE WINNER'S FRAME, AND NOTHING ELSE (Chef, 2026-09-22 TG 11656, a second
     Hearthstone reference: the gold-framed card beside the plain silver one).
     ⚠️ THIS IS A SECOND CHROMATIC ACCENT AND DESIGN.md FORBIDS ONE — §"The One Chromatic Accent
     Rule" (blood is the commit key alone) and §"Don't reintroduce a second chromatic accent —
     emphasis is brightness here, not hue". Chef asked for it directly and was told it crosses that
     rule; his call is final. What the rule was PROTECTING is kept: gold never touches a readout, a
     legend, a control or a link, it is only ever the FRAME of the one winning row, and it is
     desaturated and dark enough that it cannot compete with the commit key for "the irreversible
     act". Blood still owns that, alone.
     ⛔ AND IT IS METAL, NOT GLOSS. DESIGN.md's Matte Rule stands: this is a lit edge and a warm
     riser — the same treatment the keys took from the first Hearthstone reference — never a shiny
     gradient laid over the row. A real gold edge is light catching a bevel; a sticker is a
     gradient. Only the first one is here. */
  --gold:#B08A3C;            /* the frame */
  --gold-hi:#E0BE72;         /* where the light catches the top lip */
  --gold-lo:#6B5220;         /* the underside, in shadow */
  --gold-glow:rgba(224,190,114,.15);

  /* BLOOD — the commit key and nothing else (owner's call, 2026-09-21: the colour of blood,
     with a tint of orange in the lit face) */
  --blood-hi:#B0221A;
  --blood:#8E1116;           /* bone on this face: 8.19:1 */
  --blood-lo:#5C0A0E;
  --blood-ink:#FDECEA;
  --blood-dormant:#EA8A80;   /* the key's identity before there is anything to press */

  --lead:#F3F1EC;            /* the lit lamp on the leading strip */
  --ok:#79C08C;              /* a reading we took ourselves */
  --warn:#E8654A;            /* a route that cannot execute */

  --r-cap:5px;               /* keycap corner */
  --r-well:3px;              /* milled recess corner */

  --s1:4px; --s2:8px; --s3:12px; --s4:18px; --s5:28px; --s6:44px;

  --ease:cubic-bezier(.2,.8,.25,1);
  --snap:cubic-bezier(.16,1,.3,1);

  --mono:"Martian Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  --sans:"Archivo",system-ui,-apple-system,"Segoe UI",sans-serif;

  /* the material. Generated, not downloaded: a directional brush over a fine anodic grain,
     wrapped so it tiles without a seam. */
  --grain:url(assets/chassis.png);
  --grain-well:url(assets/well.png);
}

*,*::before,*::after{box-sizing:border-box}

html,body{height:100%}
body{
  margin:0;
  background:var(--bench);
  color:var(--legend);
  font-family:var(--sans);
  font-size:15px;
  line-height:1.45;
  -webkit-font-smoothing:antialiased;
  overflow:hidden;                       /* the instrument does not scroll */
  overscroll-behavior:none;
}

.sprite{position:absolute;width:0;height:0}
.ico{width:16px;height:16px;flex:none;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}
.ico--tok{width:15px;height:15px}

/* ── the bench ───────────────────────────────────────────────────────────────────────────── */
.bench{
  height:100dvh;
  padding:clamp(8px,1.5vmin,20px);
  padding-top:max(clamp(8px,1.5vmin,20px),env(safe-area-inset-top));
  padding-bottom:max(clamp(8px,1.5vmin,20px),env(safe-area-inset-bottom));
  display:grid;
  background:
    radial-gradient(120% 90% at 50% -10%, #17191B 0%, var(--bench) 58%, var(--bench-edge) 100%);
}

/* ── the panel: one milled face, seams where parts meet ─────────────────────────────────── */
.panel{
  min-height:0;
  display:grid;
  /* ⛔ THE COLUMN TRACK MUST BE SHRINKABLE, AND THIS IS THE LINE THAT WAS MISSING (2026-09-21).
     Only the ROWS were declared, so the single implicit COLUMN was `auto` — which resolves to the
     widest row's MAX-content. The footer is a nowrap flex row, so its full sentence sized the track
     to 1652.58px inside a 1252px panel, and `overflow-x:hidden` below silently swallowed the
     difference: the board's right-hand columns and the SWAP key were cut off with no scrollbar to
     hint that anything was missing. minmax(0,1fr) lets the track be the panel's width, and the
     children's own min-width:0 then does the rest. ⚠️ It had NOTHING to do with the typed amount
     — it was there at "1" too; it only needed a connected wallet to put text in the footer. */
  grid-template-columns:minmax(0,1fr);
  grid-template-rows:auto minmax(0,1fr) auto;
  position:relative;
  border-radius:8px;
  background:
    var(--grain),
    linear-gradient(180deg, var(--chassis-hi) 0%, var(--chassis) 46%, var(--chassis-lo) 100%);
  background-blend-mode:soft-light,normal;
  background-size:256px 256px,auto;
  border:1px solid #141618;
  box-shadow:
    0 1px 0 rgba(255,255,255,.055) inset,          /* the machined top edge catching light */
    0 22px 48px -22px rgba(0,0,0,.92),
    0 3px 10px -4px rgba(0,0,0,.6);
  overflow:hidden;
}

/* ── head: etched mark, instrument screen ──────────────────────────────────────────────── */
.panel__head{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  padding:var(--s3) var(--s4);
  border-bottom:1px solid var(--hairline);
  background:linear-gradient(180deg,rgba(255,255,255,.03),transparent);
}

.mark{display:flex;align-items:baseline;gap:var(--s3);min-width:0}
.mark__word{
  font-family:var(--sans);font-weight:700;
  font-size:clamp(17px,2.1vmin,23px);letter-spacing:-.022em;color:var(--legend);
  text-shadow:0 1px 0 rgba(255,255,255,.10),0 -1px 0 rgba(0,0,0,.55);
}
.mark__rule{width:1px;align-self:stretch;background:var(--hairline);flex:none}
.mark__sub{
  font-family:var(--mono);font-size:10px;font-weight:400;letter-spacing:.09em;
  color:var(--legend-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  text-shadow:0 1px 0 rgba(255,255,255,.05);     /* cut into the metal, like the wordmark */
}

.screen{
  position:relative;flex:none;
  padding:7px 12px;border-radius:var(--r-well);
  background:var(--well);
  border:1px solid #0A0805;
  box-shadow:0 2px 5px rgba(0,0,0,.6) inset,0 0 0 1px rgba(243,241,236,.05);
}
.screen__glass{
  position:absolute;inset:0;border-radius:var(--r-well);pointer-events:none;
  background:linear-gradient(180deg,var(--live-glow),transparent 42%);
}
.screen__grid{display:flex;gap:18px;margin:0}
/* each readout centres on its own heading (Chef, 2026-09-21 TG 11211) — the value is usually wider
   than the label above it, so left-aligning both made the row read as ragged columns. */
.screen__cell{display:flex;flex-direction:column;gap:1px;min-width:0;align-items:center;text-align:center}
.screen dt{font-family:var(--mono);font-size:10px;letter-spacing:.12em;color:var(--live-2)}
.screen dd{
  margin:0;font-family:var(--mono);font-size:12px;font-weight:600;
  color:var(--live);font-variant-numeric:tabular-nums;letter-spacing:-.02em;
  text-shadow:0 0 9px var(--live-glow);
}
.screen dd[data-state="down"]{color:var(--warn);text-shadow:none}
.screen dd:empty::before{content:"\2014\2014\2014\2014";color:var(--live-2)}

/* the BOARD cell's value is a button: same readout, now pressable. No chrome of its own — it is
   the reading, and the only tell is the cursor and the focus ring. */
.screen__act{
  font:inherit;color:inherit;letter-spacing:inherit;
  background:none;border:0;padding:0;cursor:pointer;
  font-variant-numeric:tabular-nums;text-shadow:inherit;
}
.screen__act:empty::before{content:"\2014\2014\2014\2014";color:var(--live-2)}
.screen__act:focus-visible{outline:2px solid var(--legend);outline-offset:3px}

/* ⭐ On DESKTOP the three cluster legends are centred over the controls they name (Chef, 2026-09-22
   TG 11648). Scoped to ≥901px on purpose: the mobile layout already gives YOU RECEIVE a right edge
   to hang from and MAX SLIP its own centred column, and re-centring them there would undo both. */
@media (min-width:901px){
  .field > label[for="amount"],
  #recv-legend,
  #slip-legend{text-align:center}
}

/* ── PULL TO PRICE AGAIN ── sits above the panel's own top edge and is only visible while pulled.
   Transform-only, so a pull costs no layout. Matte, no colour: the one chromatic accent on this
   page is the commit key. */
.pull{
  /* ⛔ FIXED, NOT ABSOLUTE, AND NOT INSIDE `.panel`. The panel sets `overflow:hidden`, so an
     indicator parked above its top edge is clipped and can never be seen — which is exactly how
     this shipped invisible the first time it was written. Fixed also matches what the gesture
     looks like natively: it comes from the top of the SCREEN. */
  position:fixed;left:0;right:0;top:0;z-index:40;
  transition:transform .18s var(--ease), opacity .18s var(--ease);
  display:flex;align-items:center;justify-content:center;gap:var(--s2);
  height:54px;pointer-events:none;
  transform:translate3d(0,-54px,0);opacity:0;
  will-change:transform,opacity;
}
.pull[data-live="1"]{transition:none}        /* no easing while a thumb is on it */
.pull[data-armed="1"] .pull__legend{color:var(--lead)}
.pull[data-armed="1"] .ico--pull{transform:rotate(180deg)}
.pull__legend{
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;color:var(--legend-3);
}
.ico--pull{
  width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.6;
  color:var(--legend-3);transition:transform .14s var(--ease);
}
@media (prefers-reduced-motion:reduce){.ico--pull,.pull{transition:none}}

/* ── body: control cluster + board ─────────────────────────────────────────────────────── */
.panel__body{
  min-height:0;
  display:grid;
  grid-template-columns:minmax(252px,24%) minmax(0,1fr);
}

/* ── control cluster ───────────────────────────────────────────────────────────────────── */
.cluster{
  min-height:0;
  padding:var(--s4);
  /* ⛔ `justify-content:space-between` PUT EVERY SPARE PIXEL INTO THE GAPS. The panel is as tall as
     the viewport and this column's content is not, so all the slack was distributed BETWEEN the
     fields — a void under the drum and another under the receive key, which is what Chef circled
     (2026-09-22, TG 11534). The controls stay together now, and the slack goes to the ONE element
     that can actually use it: the sources list, which grows with however many answered. */
  display:flex;flex-direction:column;justify-content:flex-start;
  gap:clamp(10px,2.1vh,20px);
  border-right:1px solid var(--hairline);
  background:linear-gradient(180deg,rgba(0,0,0,.05),rgba(0,0,0,.16));
}
.field{display:flex;flex-direction:column;gap:var(--s2);min-width:0}

.legend{
  font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.14em;
  color:var(--legend-3);
}
.legend--num{text-align:right}

.amountrow{display:flex;align-items:stretch;gap:var(--s2)}
/* ⭐ ONE HEIGHT FOR THE THREE CONTROLS ON THE SAME LINE — amount box, pay key, receive key.
   ⛔ NOT A MAGIC NUMBER: it is derived from the SAME clamp that sizes the amount's own text, plus
   its line box and padding (6px × 2 + 1px border × 2), so it tracks the font at every viewport
   instead of drifting away from it. A hardcoded 40px matched one phone and nothing else.
   Chef reported the mismatch on mobile (TG 11517) and then on desktop (TG 11535); measured before
   the fix, desktop was amount 45 / pay 45 / receive 35. */
:root{--ctl-font:clamp(20px,2.9vmin,28px);--ctl-h:calc(var(--ctl-font) * 1.2 + 14px)}
/* ⚠️ Scoped to the amount ROW on purpose: `.amount` is also worn by the slip box inside the
   detent grid (`input.amount.detent-box`), which is 27px and must stay that way. */
.amountrow .amount{height:var(--ctl-h)}
.amount{
  flex:1;min-width:0;line-height:1.2;
  font-family:var(--mono);font-size:var(--ctl-font);font-weight:600;
  font-variant-numeric:tabular-nums;letter-spacing:-.04em;
  color:var(--legend);background:var(--chassis-well);
  border:1px solid #141618;border-radius:var(--r-well);
  box-shadow:0 2px 5px rgba(0,0,0,.45) inset;
  padding:6px 10px;width:100%;
}
.amount:focus-visible,#picker-q:focus-visible{outline:2px solid var(--legend);outline-offset:1px}

/* keycaps: a bone cap sitting proud of the chassis */
.keycap{
  display:flex;align-items:center;justify-content:center;gap:7px;
  font-family:var(--mono);font-weight:600;letter-spacing:.03em;
  color:var(--cap-ink);cursor:pointer;
  background:linear-gradient(180deg,var(--cap-hi),var(--cap) 62%,var(--cap-lo));
  border:1px solid #6E6A61;border-radius:var(--r-cap);
  box-shadow:0 2px 0 #7C7870,0 4px 7px -2px rgba(0,0,0,.7);
  transition:transform .09s var(--snap),box-shadow .09s var(--snap);
}
.keycap:active{transform:translateY(2px);box-shadow:0 0 0 #7C7870,0 1px 3px -1px rgba(0,0,0,.7)}
.keycap:focus-visible{outline:2px solid var(--legend);outline-offset:2px}
.keycap--token{flex:none;padding:5px 12px}

.hint{margin:0;font-size:11px;line-height:1.4;color:var(--legend-3)}
.keycap__sym{font-size:13px;line-height:1.1;max-width:9ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.keycap--recv{width:100%;height:var(--ctl-h);padding:0 12px;justify-content:flex-start}
.keycap__addr{margin-left:auto;font-size:10px;letter-spacing:-.02em;color:#5E5A53}

/* preset keys: the fast path */
.presets{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s1)}
/* ⭐ THE SMALL KEYS ARE KEYS — Chef, 2026-09-22 (TG 11537), on a Hearthstone reference: a plate
   seated in a machined channel, lit along its top edge, that you can see is pressable.
   ⛔ WHAT WAS TAKEN FROM IT AND WHAT WAS NOT. Taken: the DEPTH and the TRAVEL — a riser under the
   key, a lit top edge, a dark underside, and 2px of movement when it goes down. Not taken: the
   GLOSS. `DESIGN.md` forbids gloss, glass and bevel costume in three separate places, and the
   thing that makes a real console key satisfying is that it MOVES, not that it shines.
   ⭐ And they are `--cap-dark`, not bone: the token keys are bone because they are the primary
   act, and a page where everything is bone has no hierarchy left. That token already existed
   ("the same key, unlit") and had never been used — the design system had the answer in it.
   A SELECTED KEY STAYS DOWN, which is what a real latching switch does, so the state is carried
   by position as well as by tone. */
.preset,
.detent{
  font-family:var(--mono);font-size:11px;font-weight:600;color:#B9BEC4;cursor:pointer;
  padding:6px 0;border-radius:var(--r-cap);
  background:linear-gradient(180deg,#3B3F43 0%,var(--cap-dark) 55%,#272A2D 100%);
  border:1px solid #141618;
  box-shadow:0 1px 0 rgba(255,255,255,.07) inset,
             0 2px 0 #17191B,
             0 3px 5px -2px rgba(0,0,0,.65);
  transition:transform .09s var(--snap),box-shadow .09s var(--snap),
             background .12s var(--ease),color .12s var(--ease),
             text-shadow .14s var(--ease);
}
/* ⭐ ONE WORD BREATHES WHILE THE BOARD IS STILL ASKING (UI audit [32]). Measured on a real load:
   the DOM did not change for 5.6 s, then not again for 5.7 s — two dead stretches in a 12.9 s wait,
   with no motion anywhere on the page. A row that is dim and still is indistinguishable from a row
   that has given up.
   ⛔ NOT A GLOW AND NOT A SPINNER. `DESIGN.md`'s Matte Rule and its "the only luminous thing is the
   measured readout" both hold: this is the PRICING word changing opacity, nothing else, and it is
   the one element on the page that is explicitly saying "not yet". A provisional row has no
   measurement to be luminous about.
   ⚠️ Guarded by `prefers-reduced-motion`, like every other movement here. */
@media (prefers-reduced-motion:no-preference){
  .strip--provisional .strip__word{animation:pricing 1.4s ease-in-out infinite alternate}
  @keyframes pricing{from{opacity:.42}to{opacity:1}}
}

/* ⭐⭐ PRESS FEEDBACK WAS INVERTED, AND THE MONEY KEY WAS ON THE WRONG SIDE OF IT (UI audit [84]).
   Measured by forcing each pseudo-state and counting the pixels that changed inside the control's
   own box: preset hover 58.4% / active 0.0%; detent 58.4% / 0.0%; REFRESH 55.2% / 0.0%; the
   disclosure latch 7.5% / 0.0% — and the other way round on the raised keys: receive keycap hover
   0.0% / active 12.3%, and the BLOOD COMMIT KEY, the one control that spends real money, hover
   0.0%. ⇒ On a phone (`hover:hover` false) the presets, detents, REFRESH, the latch and every
   picker row returned NOTHING on tap — the first sign anything had happened was the amount changing,
   a repaint and a re-quote away. On a desktop the key that spends money did not acknowledge the
   pointer at all. ⭐ The presets and detents have since been given their travel; these are the rest.
   ⛔ AND THE HOVERS ARE GUARDED. An unguarded `:hover` STICKS after a tap on iOS, so the last thing
   you touched stays lit beside a genuinely latched key — a lie about which one is selected. Every
   hover on this page sits inside `hover:hover and pointer:fine` for that reason; the press states
   below are deliberately NOT guarded, because a press is real on every input. */
.iconbtn:active,
.tokrow:active,
.picker__close:active{transform:translateY(1px);box-shadow:0 1px 4px rgba(0,0,0,.5) inset}
.latch:active{transform:translateY(1px)}
@media (hover:hover) and (pointer:fine){
  /* ⚠️ NOT `--cap-hi` on the keycap: measured, it changes 46.6% of the cap — that is a state change,
     not a hover. A 1px lift of the shadow ledge says "this is pressable" without saying "this is
     selected". */
  .keycap:hover:not(:disabled){box-shadow:0 1px 0 rgba(255,255,255,.28) inset,0 3px 0 #7C7870,
                               0 4px 7px -2px rgba(0,0,0,.6)}
  .commitkey:hover:not(:disabled){filter:brightness(1.08)}
}

/* ⭐ THE SELECTION HIGHLIGHT IS OURS (UI audit [70]). Left alone, dragging across the control
   cluster paints the browser's default saturated blue — a hue from outside this palette entirely,
   arriving at full strength on the one surface the design keeps most neutral. It is also the single
   easiest thing on the page for a user to trigger by accident while trying to select an amount.
   ⛔ NOT a fourth accent: bone at low alpha over the chassis, which is the same luminance-carries-
   emphasis rule the readouts use. */
::selection{background:rgba(243,241,236,.22);color:#FFFDF8}
::-moz-selection{background:rgba(243,241,236,.22);color:#FFFDF8}

/* ⭐⭐ QUOTE SER — THE ONLY THING THAT ASKS FOR A LIVE BOARD (Chef, 2026-09-22 TG 11649).
   Thin and full-width under MAX SLIP, so it reads as the bottom rail of the whole input cluster
   rather than a fifth sibling of the slip detents. Same key construction as its neighbours — riser,
   lit top edge, 2px of travel — because it is the same kind of object; what makes it primary is
   WIDTH and the lamp, not a different material.
   ⭐ IT IS LIT WHEN IT IS THE THING TO DO. `data-armed="1"` means the board on screen does not
   answer the question currently in the controls (nothing priced yet, or the pair/amount/slip moved
   under it). Armed, the label carries the same filament the measured readouts use, so the page
   says "ask me" in the vocabulary it already speaks. Unarmed it goes quiet — a board that is
   already current has nothing to ask for. */
.quotekey{
  grid-column:1/-1;width:100%;margin-top:7px;
  font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.13em;
  color:#B9BEC4;cursor:pointer;padding:7px 0;border-radius:var(--r-cap);
  background:linear-gradient(180deg,#3B3F43 0%,var(--cap-dark) 55%,#272A2D 100%);
  border:1px solid #141618;
  box-shadow:0 1px 0 rgba(255,255,255,.07) inset,
             0 2px 0 #17191B,
             0 3px 5px -2px rgba(0,0,0,.65);
  transition:transform .09s var(--snap),box-shadow .09s var(--snap),
             background .12s var(--ease),color .12s var(--ease),
             text-shadow .14s var(--ease);
}
.quotekey[data-armed="1"]{color:var(--live);text-shadow:0 0 7px var(--live-glow)}
.quotekey:focus-visible{outline:2px solid var(--legend);outline-offset:2px}
.quotekey:active:not(:disabled){transform:translateY(2px);
  box-shadow:0 0 0 #17191B,0 1px 2px rgba(0,0,0,.6) inset}
.quotekey:disabled{cursor:default;opacity:.55;text-shadow:none}
@media (hover:hover) and (pointer:fine){
  .quotekey:hover:not(:disabled){
    background:linear-gradient(180deg,#44484C 0%,#383C40 55%,#2B2E31 100%);
    color:#FFFDF8;
    text-shadow:0 0 2px rgba(255,253,248,.85),
                0 0 9px rgba(243,241,236,.50),
                0 0 20px rgba(243,241,236,.22);
  }
}

/* ⭐ THE NUMBER LIGHTS UP, NOT THE BUTTON (Chef, 2026-09-22 TG 11543). A colour change from grey
   to white is a state; a filament coming on is an INSTRUMENT. The page already owns this
   vocabulary — the status screen and the drum's readout both glow on `--live-glow` — so the keys
   borrow it rather than inventing a second idea.
   ⛔ `hover:hover and pointer:fine`, NOT a width query: on a touch screen a :hover sticks after
   the tap and the last key you pressed stays lit, which is a lie about the state. A phone gets
   the press, which it can feel, and none of this. */
@media (hover:hover) and (pointer:fine){
  .minikey:hover{
    background:linear-gradient(180deg,#44484C 0%,#383C40 55%,#2B2E31 100%);
    color:var(--live);
    text-shadow:0 0 2px rgba(255,253,248,.7),0 0 8px rgba(243,241,236,.40);
  }
  /* the disclosure toggle is text, not a key — it gets the lamp but never a riser */
  .latch:hover{color:var(--live);text-shadow:0 0 2px rgba(255,253,248,.7),0 0 9px rgba(243,241,236,.38)}
  .preset:hover:not(:disabled),
  .detent:hover{
    background:linear-gradient(180deg,#44484C 0%,#383C40 55%,#2B2E31 100%);
    color:#FFFDF8;
    /* a filament, not a colour change: a tight bright core, a mid bloom, and a wide soft halo.
       ⚠️ This is the ONE place the page lights something that is not a measured reading —
       DESIGN.md's own line is "the only luminous thing is the measured readout". Chef asked for
       it directly (TG 11543) and was told it crosses that rule. Held to hover on a fine pointer
       so it is a response to the user's hand, never a permanent second light source. */
    text-shadow:0 0 2px rgba(255,253,248,.85),
                0 0 9px rgba(243,241,236,.50),
                0 0 20px rgba(243,241,236,.22);
  }
}
/* the latched key carries a dimmer version of the same lamp, always — it IS the live setting, and
   this is what made it readable at a glance rather than only by its slightly paler text */
.preset[aria-pressed="true"],
.detent[aria-checked="true"]{text-shadow:0 0 7px var(--live-glow)}
.preset:focus-visible,
.detent:focus-visible{outline:2px solid var(--legend);outline-offset:2px}
.preset:active:not(:disabled),
.detent:active{transform:translateY(2px);
  box-shadow:0 0 0 #17191B,0 1px 2px rgba(0,0,0,.6) inset}
/* the latched key: down in its well, and it stays there */
.preset[aria-pressed="true"],
.detent[aria-checked="true"]{
  /* ⚠️ FIRST ATTEMPT MADE THIS A HOLE. Seating the key and darkening its face is physically
     truthful — a key that is down sits in shadow — but it made the CHOSEN option the least
     legible thing in the row, which is backwards: the setting the user is actually on has to be
     the most readable. So it stays DOWN, and it is LIT: a bright rim where the light catches the
     lip of the recess, and a face brighter than its unpressed neighbours. Down and live, which is
     what a latching switch with a lamp in it actually looks like. */
  transform:translateY(2px);color:var(--live);
  background:linear-gradient(180deg,#4A4F54 0%,#3C4045 60%,#33373B 100%);
  border-color:#0E1012;
  box-shadow:0 1px 0 rgba(255,255,255,.16) inset,
             0 2px 6px rgba(0,0,0,.55) inset,
             0 0 0 #17191B;
}
.preset:disabled{opacity:.42;cursor:not-allowed;box-shadow:0 2px 0 #17191B}
@media (prefers-reduced-motion:reduce){.preset,.detent{transition:background .12s,color .12s}}

/* the knurled wheel, and the readout that makes it an instrument rather than a flourish */
.dialrow{display:flex;align-items:center;gap:var(--s2)}
/* the share readout, in the style of a calculator display: the unlit segments sit behind at low
   opacity so the lit digits read as segments rather than as text (Chef, TG 11278) */
.dial__pct{
  position:relative;flex:none;min-width:4.6ch;text-align:right;
  font-family:var(--mono);font-size:13px;font-weight:600;
  font-variant-numeric:tabular-nums;letter-spacing:.01em;
  color:var(--live);text-shadow:0 0 7px rgba(243,241,236,.30);
}
.dial__pct::before{
  content:attr(data-ghost);position:absolute;inset:0;text-align:right;
  color:var(--live);opacity:.10;pointer-events:none;
}
.dial__pct[data-off="1"]{opacity:.38}
/* ── THE DRUM ── a disc lying flat, seen from just above its front edge. Two faces of ONE object:
   the flat TOP (an ellipse — plain, lathe-turned, ⛔ no lines on it: the knurl is cut into the rim,
   not the face — Chef, 2026-09-22) and the knurled RIM below it.
   The SHAPE is the silhouette: the top ellipse's far edge bows up, its near edge bows down over the
   rim, and the rim's bottom edge bows down by the same ellipse (border-radius 50% / --drum-e). A
   rounded rectangle with corners is what read as "a square with lines across it" (TG 11283).
   The ROUNDNESS is the shading: the rim is lit where it faces you and falls away to near-black at
   each side as cos(angle) (::before), and the ridges bunch and thin toward those sides because
   app.js places each one by its angle on the drum. No 3D transforms, no gloss, no sliding gradient.
   --drum-e is the top ellipse's minor radius; every other dimension derives from it. */
.dial{
  --drum-e:7px;
  position:relative;flex:1;height:34px;cursor:ew-resize;touch-action:none;
  /* ⛔ A DRUM IS A CONTROL, NOT TEXT. Without this a press starts a native SELECTION drag —
     `selectstart` fires on the ridge under the thumb — and the browser paints its own no-drop
     cursor (the circle with a line through it) OVER `ew-resize` for as long as you hold.
     Chef saw it 2026-09-22 at the bottom stop, where the drum cannot move in the direction you
     are pulling, so the selection is the only thing that answers. */
  user-select:none;-webkit-user-select:none;-webkit-user-drag:none;
  filter:drop-shadow(0 3px 5px rgba(0,0,0,.55));
}
.dial[data-off="1"]{opacity:.38;cursor:default}
.dial__top{
  position:absolute;left:0;right:0;top:0;height:calc(var(--drum-e)*2);z-index:5;
  border-radius:50%;
  border:1px solid #0B0D0F;
  /* matte anodised face lit from above-front: a hair brighter toward the near edge, and the
     concentric grain of a turned disc. Nothing runs ACROSS it. */
  background:
    repeating-radial-gradient(ellipse at 50% 50%, rgba(255,255,255,.05) 0 1px, rgba(0,0,0,0) 1px 4px),
    linear-gradient(180deg,#2F3438 0%,#3C4247 45%,#4D5359 100%);
  box-shadow:0 -1px 0 rgba(255,255,255,.16) inset, 0 1px 1px rgba(0,0,0,.5) inset;
}
.dial__face{
  position:absolute;left:0;right:0;top:var(--drum-e);bottom:0;overflow:hidden;
  border-radius:0 0 50% 50% / 0 0 var(--drum-e) var(--drum-e);
  border:1px solid #0B0D0F;border-top:0;
  /* the rim, top to bottom: brightest just under the lip where it faces the light, rolling away
     into shadow underneath. Matte: a broad fall-off, no specular stripe. */
  background:linear-gradient(180deg,#858C93 0%,#6D747B 20%,#4C5258 56%,#2B2F33 86%,#1B1E21 100%);
}
/* the curvature left to right: the rim faces you in the middle and turns away toward each side, so
   the light falls off as cos(angle) — ambient plus diffuse, so the sides go dark but not to a hard
   black line. It sits ABOVE the ridges so they sink into the shadow with the surface they are cut into. */
.dial__face::before{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;border-radius:inherit;
  background:
    linear-gradient(90deg,
      rgba(0,0,0,.88) 0%, rgba(0,0,0,.62) 2.5%, rgba(0,0,0,.44) 6%, rgba(0,0,0,.28) 11%,
      rgba(0,0,0,.16) 18%, rgba(0,0,0,.07) 27%, rgba(0,0,0,.02) 36%, rgba(0,0,0,0) 44%,
      rgba(0,0,0,0) 56%, rgba(0,0,0,.02) 64%, rgba(0,0,0,.07) 73%, rgba(0,0,0,.16) 82%,
      rgba(0,0,0,.28) 89%, rgba(0,0,0,.44) 94%, rgba(0,0,0,.62) 97.5%, rgba(0,0,0,.88) 100%),
    linear-gradient(90deg, rgba(255,255,255,0) 22%, rgba(255,255,255,.045) 40%, rgba(255,255,255,0) 58%);
}
/* ⛔ THE RIDGES ARE PLACED BY ANGLE, NOT EVENLY SPACED — THIS IS WHAT MAKES IT LOOK ROUND.
   A repeating gradient sliding sideways reads as a BELT MOVING BEHIND A WINDOW (Chef, TG 11283).
   On a real cylinder the markings CROWD at the edges and spread in the middle, because the surface
   there is turned away from you. Each ridge is ONE element — a lit flank, a crest and a shadowed
   flank, translucent so the rim's own shading shows through it — and app.js moves it with a
   TRANSFORM ONLY (no layout per frame): to sin(angle), narrowed by cos(angle) as it turns away,
   and on a fast turn STRETCHED along the direction of travel and dimmed in proportion, which is
   what a ridge looks like when it moves further than its own width inside one frame. */
.dial__tick{
  position:absolute;top:0;bottom:0;left:0;width:4px;
  background:linear-gradient(90deg,
    rgba(255,255,255,.34) 0%, rgba(255,255,255,.14) 40%, rgba(0,0,0,.20) 56%, rgba(0,0,0,.52) 100%);
  transform-origin:50% 50%;
  will-change:transform,opacity;
}
/* the mark is one more fixture ON the rim, at its own angle — app.js places it from sin(theta)
   exactly as it does every ridge, so it travels with the surface and can only run between the two
   ends. It rides ABOVE the side shading (z-index) because it is the indicator: it must still be
   read at the ends, where the surface it sits on has turned almost edge-on. ⛔ No CSS transition:
   every frame is painted by app.js, because each ridge moves at a DIFFERENT rate. */
.dial__mark{
  position:absolute;top:0;bottom:0;left:0;width:3px;z-index:3;
  background:linear-gradient(180deg,#FFFFFF,#EDEBE6 60%,#C4C8CC);
  box-shadow:0 0 7px rgba(243,241,236,.7), 0 0 2px rgba(255,255,255,.9);
  transform-origin:50% 50%;
  will-change:transform,opacity;
}
.dial:focus-visible{outline:2px solid var(--legend);outline-offset:2px}


.detents{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s1)}
/* .detent shares the key treatment above — see THE SMALL KEYS ARE KEYS */
.detent:focus-visible{outline:2px solid var(--legend);outline-offset:2px}

/* ── who answered ──────────────────────────────────────────────────────────────────────── */
/* ⛔ `flex:1` here let the list shrink under its own rows and print across the board at
   1280x720 — the most common laptop height, and the one viewport the first pass never shot. */
/* ⛔ NOT `flex:1`, and NOT `margin-top:auto`. `flex:1` let this shrink under its own rows and
   print across the board at 1280x720; `margin-top:auto` then pooled every spare pixel into one
   ~140px band directly above it, which reads as an unfinished column. The cluster distributes
   its slack across all four gaps instead (see `.cluster`), so the space is rhythm, not a hole. */
/* ⭐ THE SOURCES LIST BUILDS FROM THE BOTTOM (Chef, 2026-09-22 TG 11552). It takes the column's
   slack — that is what stopped the gaps inflating — but the block itself sits at the FOOT of the
   panel, so with only a few sources answering the empty space falls between MAX SLIP and the
   heading rather than under the last row. */
.field--asked{flex:1 1 auto;min-height:0;overflow:hidden;justify-content:flex-end}
.field--asked .asked{overflow:auto}
.asked{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.asked__row{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);
  padding:clamp(3px,.7vh,7px) 0;border-bottom:1px solid var(--hairline-soft);
  font-family:var(--mono);font-size:11px;letter-spacing:-.01em;color:var(--legend-3);
}
.asked__row:last-child{border-bottom:0}
.asked__row span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.asked__row em{font-style:normal;font-size:10px;letter-spacing:.1em;flex:none}
.asked__row em:empty::before{content:"\2014"}
.asked__row[data-got="yes"]{color:var(--legend-2)}
.asked__row[data-got="yes"] em{color:var(--ok)}
.asked__row[data-got="no"] em{color:var(--legend-3)}
.asked__row[data-got="lead"]{color:var(--legend)}
.asked__row[data-got="lead"] em{color:var(--live)}
.asked__row[data-got="skip"]{opacity:.62}
.asked{overflow:auto;min-height:0;overscroll-behavior:contain}

.strip--provisional{opacity:.55}
.strip--provisional .strip__out{color:var(--legend-3)}
/* ── the board: a deep well milled into the panel ──────────────────────────────────────── */
.board{
  min-height:0;min-width:0;
  display:grid;grid-template-rows:auto minmax(0,1fr) auto auto;
  background:var(--grain-well),var(--chassis-well);
  background-blend-mode:soft-light,normal;
  background-size:256px 256px,auto;
  box-shadow:0 1px 6px rgba(0,0,0,.5) inset;
}
.board__legends,.strip{
  display:grid;
  /* ⛔ EVERY COLUMN BUT ROUTE WAS RIGID, SO ROUTE PAID FOR ALL OF THEM. Five fixed tracks (136 +
     172 + 78 + 86 + 118 = 590px) plus five gaps sat in front of a `minmax(0,1fr)` ROUTE, so between
     the 900px breakpoint and about 1130px there was nothing left: measured 21px at 1000px wide,
     with its legend still printed over it. A labelled column with no room is worse than a hidden
     one — the page says "ROUTE" and then shows three characters of one.
     ⇒ Every track gets a floor and a ceiling instead of a single number. They shrink together
     toward their floors and ROUTE keeps the slack, so the row degrades evenly instead of one column
     absorbing the whole squeeze. ⭐ The legends share this template, so they stay aligned by
     construction — the alignment fix below is not re-derived, it still holds. */
  grid-template-columns:minmax(104px,136px) minmax(72px,1fr) minmax(128px,172px)
                        minmax(58px,78px) minmax(56px,86px) minmax(92px,118px);
  align-items:center;gap:var(--s3);
}
/* ⛔ THE LEGENDS MUST SIT OVER THEIR OWN COLUMNS, and they did not: measured 9px left and 3px right
   at 1920, 1440 and 1280 alike. The legends are padded to the BOARD (--s4 = 18px) while a strip's
   content starts at `.strips` padding 8 + its own 1px border + its own --s4 = 27px, and ends 8+1+12
   = 21px from the right. A screen-printed legend that does not line up with the dial it labels is
   the one thing an instrument may not get wrong. Derived, not nudged — if the spacing scale moves,
   the arithmetic in this comment is how to redo it. */
.board__legends{padding:9px 21px 9px 27px;border-bottom:1px solid var(--hairline-soft)}

.strips{list-style:none;margin:0;padding:var(--s2);display:flex;flex-direction:column;
  gap:var(--s1);min-height:0;overflow:auto;overscroll-behavior:contain}

.strip{
  position:relative;
  flex:1 1 0;max-height:132px;min-height:52px;
  padding:10px var(--s3) 10px var(--s4);
  border-radius:var(--r-well);
  background:linear-gradient(180deg,#232629,#1E2123);
  border:1px solid #17191B;
  box-shadow:0 1px 0 rgba(255,255,255,.028) inset;
}
/* the lit lamp: colour AND a shape change AND a word, never colour alone */
.strip::before{
  content:"";position:absolute;left:7px;top:50%;width:5px;height:5px;margin-top:-2.5px;
  border-radius:50%;background:#34383C;
}
/* ⭐ THE WINNING ROW IS FRAMED IN GOLD (Chef, TG 11656). The row's own fill barely changes — the
   difference is the EDGE: a warm keyline all the way round, a lit top lip, a dark underside, and a
   low warm bloom outside it. That is what separates the gold card from the silver one in his
   reference, and it is a property of the frame, not a wash over the artwork. */
.strip[data-lead="1"]{
  background:linear-gradient(180deg,#2E2C28,#252320);
  border-color:var(--gold);
  box-shadow:0 0 0 1px rgba(176,138,60,.30),
             0 1px 0 rgba(224,190,114,.22) inset,
             0 -1px 0 rgba(107,82,32,.55) inset,
             0 0 16px -4px var(--gold-glow);
}
.strip[data-lead="1"]::before{
  background:var(--gold-hi);box-shadow:0 0 9px var(--gold-glow),0 0 2px var(--gold);
}
/* the tag on the winning row is the one piece of text allowed to carry the metal */
.strip[data-lead="1"] .strip__tag{color:var(--gold-hi)}
.strip[data-dead="1"]{opacity:.62}

.strip__src{display:flex;flex-direction:column;gap:1px;min-width:0}
.strip__name{font-family:var(--sans);font-size:13.5px;font-weight:600;letter-spacing:-.012em;
  color:var(--legend);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.strip__tag{font-family:var(--mono);font-size:10px;letter-spacing:.1em;color:var(--lead)}
.strip__tag[data-kind="promoted"]{color:var(--legend-3);letter-spacing:.06em}
/* the tie tag wears the winner's metal, because the row IS holding the top slot — but it is longer
   and quieter than BEST PRICE, because it is a narrower claim */
.strip__tag[data-kind="tied"]{color:var(--gold-hi);letter-spacing:.04em;font-size:9px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
/* ⭐ THE UNMEASURED BADGE (Chef, TG 11654). Same weight as the promoted tag — it is an EXPLANATION,
   not a warning, and giving it the fault tone would read as an accusation against the rival rather
   than an honest statement about the limit of our own instrument. It is longer than the other tags
   by design (it has to carry a reason, not a label), so it is allowed to shrink rather than wrap a
   strip taller than its neighbours. */
.strip__tag[data-kind="unmeasured"]{
  color:var(--legend-3);letter-spacing:.04em;font-size:9px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;
}
.strip[data-lead="1"] .strip__name{color:#FFF}

.strip__route{font-family:var(--mono);font-size:11px;color:var(--legend-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:-.02em}

.strip__num{
  font-family:var(--mono);font-variant-numeric:tabular-nums;text-align:right;
  letter-spacing:-.045em;white-space:nowrap;
  /* ⛔ …AND IT MUST BE CUT WHEN IT DOES NOT FIT. `nowrap` alone let YOU RECEIVE run straight over
     the GAS column, so both sets of digits overlapped and NEITHER was readable — two numbers
     printed on top of each other is worse than one truncated number, because the reader cannot
     tell it is happening. A grid child needs min-width:0 or it refuses to shrink at all. */
  min-width:0;overflow:hidden;text-overflow:ellipsis;
}
/* ⭐⭐ BONE IS EARNED BY MEASUREMENT, NOT BY RANK (UI audit [62]).
   ⛔ DESIGN.md's Don't list ends with "Don't colour a rival's claimed figure as though it were
   measured", and this file's own comment a few lines down says a claim "does not get the measured
   field's colour" — but that comment guards `.strip__state`, the WORD, not the NUMBER a trader
   actually reads. Measured: `--legend` #EDECE8 has relative luminance 0.8382 and `--live` #F3F1EC
   has 0.8802 — a ratio of 1.047:1 between them, i.e. no perceptible step at all. So an unmeasured
   claim and a simulated fill were printed at the same brightness, and the page's one luminance
   semantic was carrying nothing.
   ⭐ This is option C in colour (Chef, TG 11653): only a row we measured can hold BEST PRICE, and
   now only a row we measured is printed in the measured tone. Same rule, said twice, which is what
   an instrument should do — a state should be legible from more than one cue.
   ⚠️ The base steps DOWN to `--legend-2`; nothing gets brighter, so no claim is flattered. */
.strip__out{font-size:15px;font-weight:600;color:var(--legend-2)}
.strip[data-state="measured"] .strip__out{color:var(--live)}
.strip[data-lead="1"] .strip__out{color:var(--live);text-shadow:0 0 10px var(--live-glow)}
/* ⚠️ The clamp that stops the FIGURE colliding with the GAS column would otherwise cut this line
   too — and this is prose, not a number. Measured after that fix: "quoted 0.01% more than it pa…"
   wanted 362px in a 172px box. A number must be cut rather than overlap its neighbour; an
   explanation must WRAP rather than be cut, or the sentence that justifies the figure is the thing
   we throw away. Two lines, then it ellipsises. */
.strip__sub{display:block;font-size:10px;font-weight:400;color:var(--legend-3);letter-spacing:.01em;
  white-space:normal;line-height:1.25;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.strip__gas,.strip__cut{font-size:11.5px;color:var(--legend-2)}

.strip__state{display:flex;align-items:center;gap:6px;min-width:0}
.strip__state .ico{width:15px;height:15px}
.strip__word{font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.08em;
  white-space:nowrap}
.strip[data-state="measured"] .strip__state{color:var(--ok)}
/* a rival's claim is NOT live measured data, so it does not get the measured field's colour */
.strip[data-state="claimed"] .strip__state{color:var(--legend-2)}
.strip[data-state="reverts"] .strip__state{color:var(--warn)}
.strip[data-state="unchecked"] .strip__state{color:var(--legend-3)}

/* the authored moment: a strip re-seats when its measurement lands.
   Exponential ease-out from an already-visible default — the row is never hidden. */
@keyframes reseat{
  0%{transform:translateY(var(--from,-14px)) scaleX(.995);filter:brightness(1.5)}
  100%{transform:none;filter:none}
}
.strip[data-reseat="1"]{animation:reseat .42s var(--snap) both}

.strip--ghost{
  display:flex;align-items:center;justify-content:center;min-height:56px;flex:0 0 auto;
  background:transparent;border:1px dashed var(--hairline-soft);box-shadow:none;
}
.strip--ghost::before{display:none}
.strip__wait{font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--legend-3)}

/* ── the reading bay: the leading route's arithmetic, every term from the same response ──── */
/* ⭐ THE RESULT SLOT CARRIES THE SAME FRAME (Chef, TG 11656: *"get this golden look onto our result
   slot"*). The bay IS the result slot — it is the winning row opened out — so it takes the winning
   row's edge rather than a treatment of its own, and the two read as one object.
   ⛔ THE FIGURE INSIDE IT DOES NOT CHANGE. It stays bone-white with its own bloom, because it is the
   MEASURED READOUT and DESIGN.md's surviving half of the accent rule is that measured data is
   carried by luminance. Gold frames the answer; it never becomes the answer. */
.bay{
  min-height:0;overflow:hidden;
  display:flex;flex-direction:column;gap:var(--s2);justify-content:center;
  padding:clamp(10px,2vh,26px) var(--s4);
  margin:0 var(--s2) var(--s2);
  border-radius:var(--r-well);
  background:linear-gradient(180deg,rgba(0,0,0,.20),rgba(0,0,0,.34));
  border:1px solid var(--gold);
  box-shadow:0 0 0 1px rgba(176,138,60,.22),
             0 1px 0 rgba(224,190,114,.16) inset,
             0 -1px 0 rgba(107,82,32,.45) inset,
             0 0 26px -8px var(--gold-glow);
}
/* the hairlines that divide the bay warm with it, so the frame reads as one piece of metal rather
   than a gold border drawn around a grey box */
.bay__head{border-bottom-color:rgba(176,138,60,.30)}
.bay__sum{border-top-color:rgba(176,138,60,.30)}
.bay__head{display:flex;align-items:baseline;gap:var(--s3);
  padding-bottom:var(--s2);border-bottom:1px solid var(--hairline-soft)}
.bay__src{font-family:var(--sans);font-size:13px;font-weight:600;color:var(--legend-2);
  letter-spacing:-.012em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* the answer, at the scale an instrument gives its primary readout */
.bay__net{margin:0;display:flex;align-items:baseline;gap:var(--s3);flex-wrap:wrap}
.bay__figure{
  font-family:var(--mono);font-variant-numeric:tabular-nums;font-weight:600;
  font-size:clamp(30px,6.6vh,66px);line-height:.96;letter-spacing:-.055em;
  color:var(--live);text-shadow:0 0 34px var(--live-glow);
}
.bay__figure:empty::before,.term__v:empty::before{content:"\2014";color:var(--legend-3)}
.bay__unit{font-family:var(--mono);font-size:clamp(11px,1.5vh,15px);font-weight:600;
  letter-spacing:.11em;color:var(--live-2)}

.bay__sum{display:flex;align-items:flex-end;gap:clamp(10px,2.2vw,30px);flex-wrap:wrap;
  padding-top:var(--s2);border-top:1px solid var(--hairline-soft)}
.term{display:flex;flex-direction:column;gap:3px;min-width:0}
.term__k{font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.13em;
  color:var(--legend-3);white-space:nowrap}
.term__v{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.045em;
  font-size:clamp(14px,2vmin,20px);font-weight:600;color:var(--legend-2);white-space:nowrap}
.term--op{align-self:flex-end;padding-bottom:3px}
.term--op span{font-family:var(--mono);font-size:14px;color:var(--legend-3)}

.bay__line{display:none;margin:0;font-family:var(--mono);font-size:11px;
  font-variant-numeric:tabular-nums;letter-spacing:-.03em;color:var(--legend-2)}
.bay__say{margin:0;font-size:12.5px;line-height:1.55;color:var(--legend-2);max-width:78ch}
.bay__say b{color:var(--legend);font-weight:600}
.bay--empty .bay__sum,.bay--empty .bay__head{opacity:.35}

.board__foot{
  display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4);
  padding:8px var(--s4) 10px;border-top:1px solid var(--hairline-soft);
}
.board__note{
  margin:0;font-family:var(--mono);font-size:10.5px;letter-spacing:.03em;color:var(--legend-3);
}
/* the phone's copy of the leading arithmetic — the bay's row does not fit beside the foot */
.board__reading{display:none;margin:0;font-family:var(--mono);font-size:11px;
  font-variant-numeric:tabular-nums;letter-spacing:-.03em;color:var(--legend-2)}
/* ⛔ A 534px ORANGE SENTENCE WAS COMPETING WITH THE 300px COMMIT KEY (UI audit [61]).
   Measured live: `#board-note` in `--warn` reads #E8654A at y=774 with the blood key at y=830 — in
   one frame, and the orange line is LONGER and BRIGHTER than the accent it is supposed to defer to.
   ⭐ And the hues are not far apart, whatever the docs said: `--warn` 10.3° / 77% sat against
   `--blood-hi` 3.2° / 74% — **7.1 degrees**. `DESIGN.md` claimed warn "is deliberately far from the
   commit key's blood"; measured, it is the same family at a different lightness.
   ⇒ This one state carries its emphasis by BRIGHTNESS, which is the page's own stated rule
   ("emphasis is brightness here, not hue"). `--warn` keeps every one of its other uses — a
   reverting row's word, a honeypot chip, a warns bullet — because those are POINTS, not paragraphs,
   and a small dense mark in the warning colour does not compete with anything.
   ⚠️ The threshold that made this fire constantly was already fixed separately: the bad state now
   needs MORE THAN HALF the sources missing, not more than two. */
.board__note[data-kind="bad"]{color:var(--live);font-weight:600}
.board__promise{margin:0;font-size:11.5px;color:var(--legend-3);text-align:right;
  max-width:46ch;flex:none}

/* ── foot ──────────────────────────────────────────────────────────────────────────────── */
.panel__foot{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  padding:var(--s3) var(--s4);
  border-top:1px solid var(--hairline);
  background:linear-gradient(180deg,var(--chassis),var(--chassis-lo));
}
.latch{
  display:flex;align-items:center;gap:7px;cursor:pointer;
  font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.13em;
  color:var(--legend-3);background:none;border:0;padding:6px 2px;
  transition:color .12s var(--ease),text-shadow .14s var(--ease);
}
.latch:focus-visible{outline:2px solid var(--legend);outline-offset:2px;border-radius:2px}
.ico--latch{width:13px;height:13px;transition:transform .2s var(--snap)}
.latch[aria-expanded="true"] .ico--latch{transform:rotate(180deg)}

.commit{display:flex;align-items:center;gap:var(--s4);min-width:0;flex:1;justify-content:flex-end}
/* ⛔⛔ THIS LINE CARRIES THE SAFETY WARNING AND IT WAS BEING CUT OFF AT THE MOMENT OF SIGNING.
   `white-space:nowrap` + ellipsis measured 922px of sentence into 362px of box at 1440×900 and
   205px at 1280×800 — 22% of it visible on an ordinary laptop, cut at "…(max slip 0.5…", with a
   blood-red HONEYPOT — SWAP ANYWAY key beside it. What got dropped was exactly the tail the code
   appends for safety: the honeypot/tax/hook note, the "minimum widened by X% for the declared tax"
   line, and on a token pay the "Step 2: swap" half of the two-signature explanation.
   ⭐ A NUMBER MAY BE TRUNCATED; A WARNING MAY NOT. The rest of this page follows the opposite rule
   for the opposite reason — a figure that overlaps its neighbour is unreadable, so figures are cut —
   and that rule was applied here to prose by inheritance rather than by decision.
   ⚠️ `min-width:0` stays and its comment below is still right: it is what stops this paragraph
   forcing the whole commit block wider than its panel. Only the wrapping changes. Three lines is
   enough for the longest sentence the code can build; past that it still ellipsises rather than
   pushing the key off the screen. */
.commit__min{
  margin:0;font-family:var(--mono);font-size:10.5px;letter-spacing:.03em;color:var(--legend-3);
  text-align:right;font-variant-numeric:tabular-nums;
  white-space:normal;max-width:64ch;overflow:visible;
  /* ⛔ NO LINE CLAMP. A three-line clamp still ate 42 of the 170 characters of the longest warning
     the code can build — better than the 133 the nowrap ate, and still the wrong answer for a
     sentence whose whole job is to stop someone signing. The width is bounded (64ch) and
     `min-width:0` below stops the flex blowout, so the only thing that grows is HEIGHT, at the foot
     of the page, where there is room. Measured after: the full sentence renders at 1440, 1280, 1100
     and 390, and `.commit` never overflows its panel at any of them. */
  /* ⛔ min-width:0 IS LOad-BEARING, not tidying (2026-09-21). A flex item defaults to
     min-width:auto, so with white-space:nowrap this paragraph's MIN-CONTENT width is the whole
     sentence — it refused to shrink, forced .commit to 1355px inside a 1252px panel, and pushed
     the board's right-hand columns and the SWAP key clean off the screen. The ellipsis above could
     never fire because the box was never made narrower than its text. flex:1 lets it take what is
     left after the account keys and the SWAP key, and shrink below that when there is not enough. */
  min-width:0;flex:1 1 auto;
}

/* the one blood-orange key */
.acct{display:flex;align-items:center;gap:var(--s2);flex:none}
.acct__who{font-family:var(--mono);font-size:10.5px;letter-spacing:-.01em;color:var(--legend-2);white-space:nowrap}
/* the small utility keys (REFRESH, SWITCH, DISCONNECT) are keys too — otherwise two rows of the
   console press and light while everything else stays painted on, which reads as broken rather
   than as restraint. Shorter riser than the presets: they are smaller keys, not the same key. */
.minikey{
  font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.1em;color:var(--legend-2);
  background:linear-gradient(180deg,#3B3F43 0%,var(--cap-dark) 55%,#272A2D 100%);
  border:1px solid #141618;border-radius:var(--r-cap);
  padding:5px 8px;cursor:pointer;
  box-shadow:0 1px 0 rgba(255,255,255,.06) inset,0 2px 0 #17191B,0 3px 4px -2px rgba(0,0,0,.6);
  transition:transform .09s var(--snap),box-shadow .09s var(--snap),
             background .12s var(--ease),color .12s var(--ease),text-shadow .14s var(--ease);
}
.minikey:active{transform:translateY(2px);box-shadow:0 0 0 #17191B,0 1px 2px rgba(0,0,0,.6) inset}
.minikey:focus-visible{outline:2px solid var(--legend);outline-offset:2px}
.tokrow__wicon{width:18px;height:18px;border-radius:4px;flex:none}
.minikey--refresh{margin-left:var(--s3)}
.detent-box{font-size:12px;padding:5px 6px;width:100%;min-width:0;text-align:center;letter-spacing:0}
.commit__min a{color:var(--legend);text-decoration:underline;text-underline-offset:2px}
.commitkey{
  display:flex;align-items:center;justify-content:center;gap:9px;
  min-width:300px;padding:13px 26px;cursor:pointer;
  font-family:var(--mono);font-size:12px;font-weight:600;letter-spacing:.13em;
  color:var(--blood-ink);border-radius:var(--r-cap);
  background:linear-gradient(180deg,var(--blood-hi),var(--blood) 58%,var(--blood-lo));
  border:1px solid #581503;
  box-shadow:0 3px 0 #581503,0 6px 12px -4px rgba(0,0,0,.75);
  transition:transform .09s var(--snap),box-shadow .09s var(--snap);
}
.commitkey:active:not(:disabled){transform:translateY(3px);
  box-shadow:0 0 0 #581503,0 2px 5px -2px rgba(0,0,0,.75)}
.commitkey:focus-visible{outline:2px solid var(--legend);outline-offset:3px}
/* ⛔ DORMANT, NOT ABSENT. The world's one signature accent used to vanish entirely before a
   wallet connected — the state every first-time visitor sees — so the page opened with no
   identity colour at all. The key is unlit metal with its own blood-orange legend and keyline. */
#commit-label[data-danger="1"]{text-decoration:underline;text-decoration-color:var(--blood-ink);text-underline-offset:4px}
.commitkey:disabled{
  cursor:not-allowed;color:var(--blood-dormant);
  background:linear-gradient(180deg,#3A3D41,var(--cap-dark) 58%,#282B2E);
  border-color:var(--blood-lo);
  box-shadow:0 3px 0 #1A1D1F,0 5px 10px -5px rgba(0,0,0,.6);
}
.ico--commit{width:15px;height:15px;stroke-width:1.9}

/* ── the token picker ─────────────────────────────────────────────────────────────────── */
.picker[hidden],.fineprint[hidden]{display:none}
.picker{
  position:absolute;inset:0;z-index:8;display:flex;align-items:center;justify-content:center;
  padding:var(--s4);background:rgba(8,9,10,.72);
  animation:fade .18s var(--ease) both;
}
@keyframes fade{from{opacity:0}to{opacity:1}}
.picker__panel{
  width:min(420px,100%);max-height:100%;display:flex;flex-direction:column;
  border-radius:6px;border:1px solid #141618;
  background:var(--grain),linear-gradient(180deg,var(--chassis-hi),var(--chassis-lo));
  background-blend-mode:soft-light,normal;background-size:256px 256px,auto;
  box-shadow:0 24px 54px -20px rgba(0,0,0,.9);
}
.picker__head{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  padding:var(--s3) var(--s3) var(--s3) var(--s4);border-bottom:1px solid var(--hairline)}
.picker__head h2{margin:0;font-family:var(--mono);font-size:11px;font-weight:600;
  letter-spacing:.16em;color:var(--legend-3)}
.iconbtn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;
  border-radius:var(--r-well);cursor:pointer;color:var(--legend-2);
  background:var(--chassis-lo);border:1px solid var(--hairline-soft)}
.iconbtn:hover{color:var(--legend)}
.iconbtn:focus-visible{outline:2px solid var(--legend);outline-offset:2px}

.picker__search{display:flex;align-items:center;gap:var(--s2);margin:var(--s3) var(--s4) 0;
  padding:0 10px;border-radius:var(--r-well);color:var(--legend-3);
  background:var(--chassis-well);border:1px solid #141618;
  box-shadow:0 2px 5px rgba(0,0,0,.45) inset}
#picker-q{flex:1;min-width:0;border:0;background:transparent;padding:9px 0;
  font-family:var(--mono);font-size:12px;color:var(--legend);letter-spacing:-.02em}
#picker-q::placeholder{color:var(--legend-3)}

.picker__list{list-style:none;margin:0;padding:var(--s2) var(--s2) 0;overflow:auto;min-height:0}
.tokrow{
  display:flex;align-items:center;gap:var(--s3);width:100%;cursor:pointer;text-align:left;
  padding:9px var(--s3);border-radius:var(--r-well);color:var(--legend);
  background:transparent;border:1px solid transparent;
}
.tokrow:hover{background:var(--chassis-lo);border-color:var(--hairline-soft)}
.tokrow:focus-visible{outline:2px solid var(--legend);outline-offset:-2px}
.tokrow .ico{color:var(--legend-2)}
/* ⛔ A SYMBOL IS ATTACKER-CONTROLLED TEXT. It comes from a stranger's contract and one in the live
   feed is 28,161 characters long — unclamped it wrapped the picker row out of the panel. Clamped
   in three places now: here, the token keys, and the board strips. */
.tokrow__sym{font-family:var(--mono);font-size:13px;font-weight:600;letter-spacing:.01em;
  flex:none;max-width:14ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tokrow__name{font-size:12px;color:var(--legend-3);min-width:0;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.tokrow__addr{margin-left:auto;font-family:var(--mono);font-size:10px;color:var(--legend-3);
  letter-spacing:-.02em;flex:none}
.tokimg,.keyimg{width:18px;height:18px;border-radius:50%;object-fit:cover;flex:none;background:var(--chassis-well)}
.tokrow__ver{margin-left:5px;font-size:10px;color:var(--ok)}
.tokrow__qty{margin-left:7px;font-family:var(--mono);font-size:10.5px;font-weight:400;letter-spacing:-.01em;color:var(--legend-3)}
.tokrow__usd{margin-left:auto;min-width:11ch;text-align:right;font-family:var(--mono);font-size:11px;
  font-variant-numeric:tabular-nums;color:var(--legend-2);white-space:nowrap}
.tokrow__ca{width:4.5ch;text-align:right;font-family:var(--mono);font-size:10px;letter-spacing:-.02em;color:#5E5A53}
.tokrow__usd[data-kind="honeypot"]{color:var(--warn);font-weight:600;letter-spacing:.08em}
.tokrow__usd[data-kind="noexit"]{color:#C77A3C;font-weight:600;letter-spacing:.08em}
.tokrow__usd[data-kind="checking"]{color:var(--legend-3)}
.warns{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}
.warns li{display:flex;gap:8px;align-items:flex-start;font-family:var(--sans);font-size:12px;line-height:1.45;color:var(--legend-2)}
.warns li::before{content:"";flex:none;width:7px;height:7px;margin-top:5px;border-radius:50%;background:var(--warn)}
/* a fact about the token (holder share, verification) is silkscreen; only a tax or a hook — money
   leaving the swap — takes the warn tone */
.warns li[data-kind="holder"]::before,.warns li[data-kind="unverified"]::before{background:var(--legend-3)}
.warns li[data-kind="unverified"]::before{background:var(--warn)}
.receipts{list-style:none;margin:0 0 var(--s4);padding:0;font-family:var(--mono);font-size:11.5px;line-height:1.6;color:var(--legend-2)}
.receipts li{display:flex;gap:12px;flex-wrap:wrap;border-bottom:1px solid var(--hairline-soft);padding:4px 0}
.receipts__none{color:var(--legend-3)}
.receipts a{color:var(--legend)}
.picker__group--loading{color:var(--legend-2);display:flex;align-items:center;gap:8px}
/* a spinner, not a pulse (Chef TG 11153): one 12px stroke ring on the shared geometry */
.spin{width:11px;height:11px;border-radius:50%;border:1.6px solid var(--hairline);border-top-color:var(--legend);
  animation:spin .9s linear infinite;flex:none}
@keyframes spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.spin{animation:none}}
.picker__group{font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.14em;color:var(--legend-3);
  padding:10px var(--s4) 4px;list-style:none}
/* the retry inside a failed-search note: a real key, because "try again" has to be pressable */
.picker__retry{
  margin-left:8px;font-family:var(--mono);font-size:9.5px;font-weight:600;letter-spacing:.1em;
  color:var(--legend-2);cursor:pointer;padding:3px 7px;border-radius:var(--r-cap);
  background:linear-gradient(180deg,#3B3F43 0%,var(--cap-dark) 55%,#272A2D 100%);
  border:1px solid #141618;
  box-shadow:0 1px 0 rgba(255,255,255,.06) inset,0 2px 0 #17191B;
}
.picker__retry:active{transform:translateY(2px);box-shadow:0 0 0 #17191B,0 1px 2px rgba(0,0,0,.6) inset}
.picker__retry:focus-visible{outline:2px solid var(--legend);outline-offset:2px}
.picker__note{margin:0;padding:var(--s3) var(--s4) var(--s4);font-size:11.5px;line-height:1.5;
  color:var(--legend-3);border-top:1px solid var(--hairline-soft)}

/* ── the fine print: the board face swings open over the well ─────────────────────────── */
.fineprint{
  position:absolute;inset:0;z-index:5;overflow:auto;overscroll-behavior:contain;
  background:var(--grain),linear-gradient(180deg,#26292C,#1D2022);
  background-blend-mode:soft-light,normal;background-size:256px 256px,auto;
  animation:swing .3s var(--snap) both;
}
@keyframes swing{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.fineprint__inner{max-width:74ch;padding:var(--s6) var(--s6) var(--s5)}
.fineprint h2{margin:0 0 var(--s4);font-size:clamp(20px,2.6vmin,26px);font-weight:700;
  letter-spacing:-.024em;color:var(--legend)}
.fineprint h3{margin:var(--s5) 0 var(--s3);font-family:var(--mono);font-size:10px;font-weight:600;
  letter-spacing:.16em;color:var(--legend-3)}
.fineprint p{margin:0 0 var(--s3);font-size:13.5px;line-height:1.62;color:var(--legend-2);
  max-width:70ch}
.fineprint dl{margin:0;display:flex;flex-direction:column;gap:var(--s3)}
.fineprint dt{font-size:13px;font-weight:600;color:var(--legend);margin-bottom:2px}
.fineprint dd{margin:0;font-size:13px;line-height:1.6;color:var(--legend-2);max-width:70ch}
.fineprint code{font-family:var(--mono);font-size:11.5px;color:var(--live)}
.fineprint em{font-style:normal;color:var(--legend);font-weight:600}
.latch--close{margin-top:var(--s5);color:var(--legend-2)}


/* ═══════════════════════════════════════════════════════════════════════════════════════════
   RESPONSIVE — LAST IN THE FILE, ALWAYS. These override components declared above them, and at
   equal specificity the later rule wins; when this block sat higher up, every component written
   afterwards quietly beat it and the phone layout collapsed with nothing erroring.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

@media (max-width:900px){
  .panel__body{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}
  .cluster{
    border-right:0;border-bottom:1px solid var(--hairline);
    /* ⭐ THE SECOND COLUMN IS NOW CONTENT-SIZED, WHICH IS THE OTHER HALF OF THE ASK. Shrinking the
       receive key inside a 1fr column just moved the slack into a 102px dead gap; `auto` hands that
       width to the amount box, which is what Chef asked for (TG 11517). */
    /* ⭐ 50/50 — Chef, 2026-09-22 (TG 11597), looking at his phone: the `auto` second column was
       sized by the receive key alone, and once MAX SLIP moved in beside the drum its four detents
       were crushed into that width with the numbers overflowing their keys. Two equal columns give
       the detents room. ⚠️ It costs the amount box some of the width TG 11517 won for it — the
       trade I flagged when the slip row moved up, and this is him taking the other side of it. */
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:var(--s3);padding:var(--s3);
  }
  /* ⭐ MAX SLIP MOVES UP BESIDE THE DRUM (Chef, 2026-09-22 TG 11519). It used to span both columns
     on its own row underneath; the PAY field is tall because it carries the presets and the drum,
     so the space to the right of them was empty. Putting slip there costs no vertical space at all.
     ⚠️ It also forces the second column WIDER than the receive key alone needed — four detent keys
     have to fit — so the amount box gives some of TG 11517's width back. That trade is the price of
     the taller layout being shorter, and it is stated here rather than discovered later. */
  .field--recv{grid-column:2;grid-row:1}
  .field--slip{grid-column:2;grid-row:2}
  .cluster > .field:first-child{grid-column:1;grid-row:1/3}
  #slip-legend{text-align:center}
  /* the source list is a desktop luxury; the board's own note carries coverage on a phone */
  .field--asked{display:none}
  .amountrow{gap:6px}
  .amount{font-size:24px;padding:6px 8px}
  /* ⛔ THE CLAIM WRAPS FROM HERE, NOT FROM 420px. `.mark__sub` is nowrap+ellipsis by default and
     the rule that lets it wrap was locked inside `@media (max-width:420px)` — so across the whole
     440–840px band the product's one claim rendered as "THE BE…". Swept 360→1460 in 20px steps:
     clipped at every width from 480 to ~840, showing 43 of 356px at the worst.
     ⚠️ Found by the UI audit AFTER I had shipped a LONGER headline and "verified" it at 1920,
     1440, 1100 and 390 — four widths that all sit OUTSIDE the broken band. Sample the range, not
     the corners. */
  .mark{flex-wrap:wrap;gap:0 var(--s2)}
  .mark__rule{display:none}
  .mark__sub{width:100%;white-space:normal}
  .keycap--token{padding:4px 8px}
  /* ⭐ THE RECEIVE KEY IS ONLY AS WIDE AS THE COIN IT NAMES, AND IT HANGS OFF THE RIGHT EDGE
     (Chef, 2026-09-22 TG 11517, measured on his phone). It was `width:100%` — a 168px slab holding
     a four-character symbol — while the amount box beside it had 96px to render a number in. The
     width it gives up is width the amount box takes.
     ⛔ AND IT MUST BE THE SAME HEIGHT AS THE OTHER TWO. Measured before the fix: amount 40px, pay
     key 40px, receive key 35px, all three on the same row. The pay key matches because
     `.amountrow` stretches it; the receive key is in its own grid cell and had nothing to stretch
     against, so `flex:1` gives it the cell's leftover height, which is the same 40px by
     construction rather than by a number anyone has to keep in sync. */
  /* ⚠️ `flex:1` was the first attempt and it made the key 111px tall: the PAY field also holds the
     presets and the drum, so the grid row is ~220px and "fill the leftover" filled all of it.
     The height has to be the amount box's height, not the cell's — so both read one variable, and
     these are the two rules that must stay in step. */
  .field--recv{align-items:flex-end}
  .keycap--recv{width:auto;flex:none;justify-content:center;padding:0 10px}
  #recv-legend{text-align:right}
  .keycap__sym{font-size:12px}
  .amount{min-width:0;font-size:22px;letter-spacing:-.05em}
  .keycap__addr{display:none}
  .hint{display:none}
  .dial{height:28px;--drum-e:6px}

  .board__legends{display:none}
  .strip{
    flex:0 0 auto;max-height:none;min-height:0;
    /* ⛔⛔ THE WINNING ROW DID NOT SAY WHO WON, ON A PHONE. `minmax(0,1fr) auto` lets the RIGHT
       column size to its own max-content, and `.strip__sub` wraps — so a row carrying a long
       explanation ("quoted 0.02% more than it paid · gas measured by us") took the entire width and
       squeezed the SOURCE column to exactly 0px. Measured: `.strip__src` width 0, name width 0, tag
       width 0, all three still painting because `.strip__src` overflows visible — which is why it
       looked like the row was simply labelled BEST PRICE with no source at all.
       ⭐ IT HIT THE LEAD ROW HARDEST BY CONSTRUCTION: the rows with the longest sub-lines are the
       ones we have the most to say about, i.e. the measured ones, i.e. usually the winner. The one
       row whose name matters most was the one guaranteed to lose it.
       ⇒ Floor the source column at 45%. The right column still sizes to content when it is short,
       and can no longer take the whole row when it is long. */
    grid-template-columns:minmax(45%,1fr) auto;
    grid-template-areas:"src out" "route out" "state gas";
    gap:2px var(--s3);padding:10px 12px 10px 18px;
  }
  .strip__src{grid-area:src}
  .strip__route{grid-area:route}
  .strip__num.strip__out{grid-area:out;align-self:center;font-size:16px}
  .strip__state{grid-area:state}
  .strip__gas{grid-area:gas;text-align:right;font-size:10.5px}
  .strip__cut{display:none}

  /* ⛔ THE EVIDENCE STAYS ON THE PHONE. The working and the fee promise were deleted below
     900px, for the audience most likely to doubt them. The terms grid does not fit; the same
     arithmetic as one line does. */
  .bay{display:none}
  .board__reading{display:block}
  .board{display:block;overflow:auto;overscroll-behavior:contain}
  .strips{overflow:visible;display:block}
  .strip{display:grid;margin-bottom:3px}
  .board__foot{position:sticky;bottom:0;background:var(--chassis-well);
    border-top:1px solid var(--hairline);
    box-shadow:0 -14px 16px -10px rgba(0,0,0,.92)}
  /* and the list itself fades into that lip, so the last visible row is obviously cut, not broken */
  /* ⛔⛔ THE FADE WAS ON THE ELEMENT THAT CANNOT SCROLL (UI audit [03]).
     Measured at 414×896 and 390×844: `.strips` has `overflow-y:visible` and
     `scrollHeight − clientHeight = 0` — it does not scroll — and it was the element carrying the
     mask. `.board` is the one with `overflow:auto`, scrollable by 176px and 257px respectively, and
     it carried no mask at all. ⇒ **the affordance was painted on the wrong box**, so the scrolling
     edge was hard and a row came to rest sliced horizontally through the middle of the words
     "THEIR CLAIM". A row cut through the type, with no scrollbar and no fade, reads as a rendering
     fault, not as "there is more below" — and the CSS comment two lines up already stated the
     intent exactly: *the last visible row is obviously cut, not broken*.
     ⛔ AND THE MASK CANNOT SIMPLY MOVE TO `.board`: `.board__foot` is `position:sticky;bottom:0`
     INSIDE it, so a mask on `.board` fades the footer too — the line that carries the fee promise.
     ⇒ Two changes instead. (1) The list gets padding under it so the last row can clear the sticky
     foot. (2) The board SNAPS to row boundaries, so it can no longer come to rest mid-type at all —
     which is a better answer than fading a cut, and it is on-thesis for a panel whose controls are
     literally called detents. `proximity`, not `mandatory`: a mandatory snap fights a deliberate
     half-scroll and feels broken. */
  .strips{padding-bottom:calc(var(--s4) + 18px)}
  .board{scroll-snap-type:y proximity}
  .strip{scroll-snap-align:start;scroll-margin-top:6px}
  .strip{padding:8px 12px 8px 18px}
  .strips{gap:3px;padding:6px}
  .board__foot{flex-direction:column;align-items:flex-start;gap:2px;padding:4px var(--s3) 6px}
  .board__note{font-size:10px}
  .board__promise{text-align:left;max-width:none;font-size:10.5px;line-height:1.35}

  .panel__foot{flex-direction:column-reverse;align-items:stretch;gap:var(--s2);padding:var(--s3)}
  .commit{flex-direction:column-reverse;align-items:stretch;gap:var(--s2)}
  .commit__min{text-align:center;white-space:normal}
  .acct{justify-content:center}
  .commitkey{width:100%;min-width:0;padding:15px 20px}
  .latch{justify-content:center}
  .fineprint__inner{padding:var(--s5) var(--s4)}
  .picker{padding:var(--s2)}
}

@media (max-width:420px){
  /* the owner's own tagline is not a desktop ornament — it is the product's one claim */
  .mark{flex-wrap:wrap;gap:0 var(--s2)}
  .mark__rule{display:none}
  .mark__sub{font-size:8.5px;letter-spacing:.06em;width:100%;white-space:normal}
  .screen__grid{gap:12px}
  /* ⛔ CELL 4 IS THE BOARD'S AGE, AND IT IS ALSO THE PRESS-TO-REPRICE CONTROL. It was hidden on
     every phone narrower than 420px — i.e. every iPhone but a Pro Max, in portrait — so the one
     statement of how stale the price is vanished on exactly the device where a user is most likely
     to look away for a minute. The quote ages out after ~30 s. Keeping the reading is worth more
     than the 12px it costs; the grid is tightened instead. (Mobile review, 2026-09-22.) */
  .screen__grid{gap:9px}
  .screen dt{font-size:9px;letter-spacing:.08em}
  .screen dd,.screen__act{font-size:11px}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}


/* ── short viewports: five sources must FIT, not be sliced ──────────────────────────────── */
/* ⛔ A board that lists a source as ANSWERED and then clips its row to a 10px sliver is
   contradicting itself on a viewport that has the room. The air goes first: the reading bay
   gives up padding and display scale before any strip gives up its own text. */
@media (min-width:901px) and (max-height:820px){
  .bay{padding:8px var(--s4) 10px;gap:6px}
  .bay__figure{font-size:clamp(26px,5.4vh,44px)}
  .bay__head{padding-bottom:6px}
  .bay__say{font-size:12px;line-height:1.45;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .strip{min-height:46px;padding:7px var(--s3) 7px var(--s4)}
  .board__foot{padding:6px var(--s4) 7px}
  .cluster{padding:var(--s3) var(--s4)}
}

/* ⛔⛔ A PHONE IN LANDSCAPE HAD NO PRICE BOARD AT ALL. Measured at 844×390: `.board` came out
   ZERO pixels high — the locked panel gives the cluster its natural height first and there was
   nothing left, so the entire product vanished and the page looked broken rather than cramped.
   (932×430 was fine at 270px, so it only bites the short end.) The panel is deliberately locked,
   but a viewport that cannot hold both parts has to give somewhere, and scrolling the body is the
   honest place: everything stays reachable and nothing is silently zero. Found by the UI audit,
   2026-09-22. */
/* ⛔⛔ SHORT VIEWPORTS HAD THREE NESTED SCROLLERS AND NO PRICES AT ALL.
   Measured at 844×390 (phone landscape), 740×360, 896×414, 667×375 and 320×568 (iPhone SE portrait):
   **ZERO price rows hit-testable on screen, with the commit key LIVE** — and at 320×568 the board
   computed to a height of literally 0px. Scrolling the inner pane to its limit revealed none of
   them. ⇒ A trade could be started from a screen showing no number, which is the one thing this
   page must never do.
   ⛔ MY OWN EARLIER "landscape rescue" MADE IT WORSE: `.board{min-height:260px}` gave the board a
   height it could not have, so 260px of board and a 633px strip list were stacked inside a 125px
   clipped `.panel__body` — `panel__body` scrolled (window 125), `.board` scrolled (window 260), and
   `#strips` overflowed both. Three windows, none of them showing a row.
   ⭐ THE FIX IS THE PAGE'S OWN IDIOM, AND CHEF ALREADY RULED ON IT ([[p-aggreg]]): the PAGE stays
   locked and ONE PANE inside it scrolls — *"no, keep the page locked please"*. So on a short
   viewport `.panel__body` is that single pane and everything below it flows into it naturally:
   the board stops being a scroller, the strip list stops being a scroller, and there is exactly one
   thing to scroll. `html`/`body` are untouched. */
@media (max-width:900px) and (max-height:620px){
  .panel__body{overflow-y:auto;min-height:0}
  .cluster{flex:none}
  /* the board is no longer a window — it is content inside the one window */
  .board{min-height:0;overflow:visible;display:block}
  .strips{overflow:visible;max-height:none}
  .board__foot{position:static}      /* a sticky foot inside a non-scroller pins to nothing */
}

/* the `hidden` attribute must win over any display rule above — the account row stayed visible
   with display:flex while hidden (found by the wallet drill, 2026-09-21) */
[hidden]{display:none !important}
