/* =====================================================================
   styles.css — everything drawn in HTML on top of the world.

   Dark glass plates over a live 3D room. One lit accent (#cdb788) does
   every job. Mono for furniture (labels, figures, buttons), serif for
   anything that is a sentence. Hairlines, no gradient chrome, no card
   shadows on a table row.

   ONE PLATE, four sizes. Everything that floats is the same object:
   same border, same glass, same radius (--r), same lift. The only
   things allowed to differ are size and what is printed on them. That
   is what makes the top left card and the top right cluster read as one
   system rather than two arrivals.

   LAYOUT MAP — the bottom edge is a stack, not a scramble.

     desktop (>= 721px)              phone (<= 720px)
     ------------------------        ------------------------
     top left    card                top        card
     top right   chip                below it   chip
                 roomline            (roomline hidden)
     bottom rt   you  -> corner      bottom     you
     bottom lf   nav  -> hint                   nav + corner (one row)
                                                stick + jump

   Every bottom anchored thing measures up from --floor. On a phone the
   bottom-most band is reserved by --stickspace (the thumb stick) or by
   --hintrow (the walk hint), never by both, so the stack rises by
   exactly the height of whatever is actually down there.

   GLASS, measured rather than guessed. The canvas was read back with
   readPixels under every panel at the spawn view: the far end sits at
   luminance ~8, the bullpen mean at ~133, a ceiling fixture at 255.
   Contrast of ink/dim/faint over --glass was then computed for alphas
   .80 to .94 against all four backdrops. Findings:
     - --glass .80 -> .86 lifts worst-case ink from 10.15:1 to 12.60:1.
       Past .86 the plate barely moves (the backdrop is blurred first),
       so .86 is where the money runs out.
     - the real failure was never the glass, it was --faint at .34,
       which scores 2.80:1 on a BLACK plate. It is now .46 (3.91:1 over
       a fixture, 4.27:1 at the dark end) and --dim went .58 -> .66 to
       keep the two steps apart.
     - the accent on glass reads 10.78:1. It never needed help.
   ===================================================================== */

:root {
  --accent: #cdb788;
  --ink: #eef3f2;
  --dim: rgba(238, 243, 242, .66);
  --faint: rgba(238, 243, 242, .46);
  --hair: rgba(238, 243, 242, .16);

  /* panel grounds. See the measurement note above: .86 is the point
     where more alpha stops buying contrast. The deep one is for the
     lever, which carries the visitor's own numbers in small type: an
     emissive lime nameplate parked behind it was still readable through
     .86 and faintly through .93, so it goes to .96. */
  --glass: rgba(7, 9, 11, .86);
  --glass-deep: rgba(7, 9, 11, .96);
  --glass-thin: rgba(7, 9, 11, .72);   /* things that are a line, not a panel */
  /* the hairline. Measured at the far end of the room, where the ground
     behind a panel bottoms out at luminance 15: at .10 the panel edge
     separated from that ground at 1.20:1, which is not an edge. .14
     reads 1.37:1 and is still a hairline, not a rule. */
  --line: rgba(255, 255, 255, .14);
  /* A panel sitting ON something needs separation, not elevation. The old
     44px soft drop read as a card hovering above the room. */
  --lift: 0 6px 18px -12px rgba(0, 0, 0, .9);
  --inset: inset 0 1px 0 rgba(255, 255, 255, .05);

  --warn: #ffb45c;
  --bad:  #ff7a5c;
  --good: #7fd6a0;

  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --serif: "Palatino Linotype", Palatino, "Book Antiqua", "Iowan Old Style", serif;

  /* geometry the layout measures off. Change these, not the offsets. */
  --gut: 20px;                                   /* screen gutter */
  --r: 5px;                                      /* the plate radius, everywhere.
                                                    5, not 13: this is a panel on an
                                                    instrument, not a card in an app. */
  --r-ctl: 3px;                                  /* controls, tighter still */
  --safe-b: env(safe-area-inset-bottom, 0px);
  --floor: calc(14px + var(--safe-b));           /* the bottom-most row */
  --card-h: 64px;                                /* the id card, fixed */
  --col-r: 264px;                                /* the top right column, fixed */
  --stickspace: 0px;                             /* the thumb stick, if any */
  --hintrow: 36px;                               /* the walk hint band plus its gap */
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  background: #05070a;
  color: var(--ink);
  font: 14px/1.55 var(--mono);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }

#stage { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

#fade {
  position: fixed; inset: 0; background: #000; opacity: 0;
  pointer-events: none; z-index: 40;
}

/* THE PLATE. Every floating surface is one of these and none of them
   may drift. If a new panel needs a different border or radius, the
   answer is almost always that it should not. */
.card,
.chip,
.roomline,
.you,
#nav button,
#soundbtn,
.corner a,
.hint,
#doorhint,
#stick {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--glass);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

/* ------------------------------------------------------------------ *
   the badge desk
 * ------------------------------------------------------------------ */

/* The ONE gate block. This file used to carry three: a radial scrim here, a
   blurred one further down, and the real linear one at the end, each
   appended by a rebuild that never deleted its predecessor. The last one
   won and the first two were dead weight that read as live rules. */
#badge {
  position: fixed; inset: 0; z-index: 90;
  display: block;
  padding: 24px;
  /* only enough gradient at the foot to hold the type. The building keeps
     the middle and the top of the frame. */
  background:
    linear-gradient(to top, rgba(5, 7, 10, .90) 0%, rgba(5, 7, 10, .74) 22%,
                    rgba(5, 7, 10, .30) 46%, rgba(5, 7, 10, 0) 66%);
  transition: opacity .6s ease;
}
#badge.gone { opacity: 0; pointer-events: none; }



.eyebrow {
  margin: 0; font-size: 10px; letter-spacing: .26em; text-transform: uppercase;
  color: var(--accent); opacity: .82;
}


.field { display: block; margin-bottom: 20px; }
.field > span {
  display: block; margin-bottom: 8px;
  font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: var(--faint);
}
#yourname {
  width: 100%; padding: 11px 13px;
  font: 15px var(--mono); color: var(--ink);
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--line); border-radius: var(--r-ctl);
  outline: none;
}
#yourname:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(205, 183, 136, .12); }

#bodies { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; }
.body {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px; text-align: left;
  font-size: 12.5px; color: var(--dim);
  border: 1px solid var(--line); border-radius: var(--r-ctl);
  background: rgba(255, 255, 255, .02);
  transition: color .18s ease, background .18s ease, border-color .18s ease;
}
.body:hover { color: var(--ink); background: rgba(255, 255, 255, .06); }
.body.on {
  color: var(--ink); border-color: var(--accent);
  background: rgba(205, 183, 136, .09);
}
.swatch { display: flex; border-radius: 3px; overflow: hidden; flex: 0 0 auto; }
.swatch i { display: block; width: 6px; height: 17px; }




/* ------------------------------------------------------------------ *
   HUD
 * ------------------------------------------------------------------ */

#hud { opacity: 0; transition: opacity .8s ease .1s; }
#hud.in { opacity: 1; }
#hud > * { pointer-events: auto; }

/* ---- the id card, top left ---- */

.card {
  position: fixed; z-index: 30;
  top: var(--gut); left: var(--gut);
  width: 330px; height: var(--card-h);
  box-shadow: var(--lift), var(--inset);
  overflow: hidden;
}

.card-row { display: flex; align-items: center; gap: 12px; height: 100%; padding: 0 13px; }
.pfp {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: var(--r-ctl);
  color: var(--accent);
  background: rgba(205, 183, 136, .08);
  border: 1px solid rgba(205, 183, 136, .22);
}
.card-id { min-width: 0; flex: 1; }
.card-top {
  display: flex; align-items: center; gap: 6px;
  font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--faint);
}
.card-top #brand { color: var(--dim); }
.card-top a { text-decoration: none; transition: color .2s; }
.card-top a:hover { color: var(--accent); }
.card-bot { display: flex; align-items: baseline; gap: 10px; margin-top: 4px; }
#token {
  font-size: 12.5px; color: var(--dim);
  text-decoration: underline; text-underline-offset: 4px;
  transition: color .2s;
}
#token:hover { color: var(--ink); }
#token:not([href]) { opacity: .45; cursor: default; text-decoration-style: dotted; }
.cap {
  margin-left: auto; font-size: 13px; color: var(--accent);
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}

/* no handle set yet: drop the separator rather than leave it dangling */
.card-top .dot:last-child, .card-top a:empty { display: none; }
.card-top .dot:has(+ a:empty) { display: none; }

.icon {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 50%;
  color: var(--faint);
  transition: background .2s, color .2s;
  position: relative;
}
.icon:hover { background: rgba(255, 255, 255, .08); color: var(--ink); }
.icon.flashing::after {
  content: attr(data-flash);
  position: absolute; right: -2px; top: calc(100% + 2px);
  font-size: 9px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent); white-space: nowrap;
}

/* ---- the top right cluster ------------------------------------------
   Two plates in ONE column of a fixed width (--col-r), same border,
   same radius, same glass as the card on the left. Previously the chip
   was a pill and the line under it a rectangle of a different width,
   which is exactly why they read as two unrelated arrivals. Now the
   only difference between the three top plates is how much is printed
   on them.

   The chip keeps an explicit height so the line below can never slide
   underneath it. The room name reads left, the headcount reads right,
   which is the same label/figure idiom the sheets and the desk
   inspector use. */

.chip {
  position: fixed; z-index: 30; top: var(--gut); right: var(--gut);
  display: flex; align-items: center; gap: 9px;
  width: var(--col-r); height: 34px; padding: 0 13px;
  box-shadow: var(--lift), var(--inset);
  font-size: 11.5px; line-height: 1; color: var(--dim);
  white-space: nowrap;
  transition: opacity .4s;
}
.chip.hide { opacity: 0; }
.pip {
  flex: 0 0 auto;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 10px var(--accent);
  animation: pulse 2.6s ease-in-out infinite;
}
@keyframes pulse { 50% { opacity: .35; } }
#room { color: var(--ink); letter-spacing: .01em; }
.heads {
  margin-left: auto; color: var(--faint);
  font-size: 10px; letter-spacing: .06em; font-variant-numeric: tabular-nums;
}

.roomline {
  position: fixed; z-index: 30;
  /* gutter + chip height + gap */
  top: calc(var(--gut) + 34px + 8px);
  right: var(--gut); margin: 0;
  width: var(--col-r); max-width: calc(100% - var(--gut) * 2);
  padding: 11px 13px 12px;
  box-shadow: var(--lift), var(--inset);
  text-align: left;
  font-family: var(--serif); font-size: 14px; font-style: italic; line-height: 1.5;
  color: var(--dim);
}
.roomline:empty { display: none; }

/* ------------------------------------------------------------------ *
   the lever — the one place a visitor gets an answer about themselves,
   holder or not. everyone has a next rung, which is the whole reason
   this is a ladder and not twenty seats.

   It is the only plate on the page that is LIT: a hairline of accent
   along its top edge and a thin accent ring in the shadow. Nothing
   else gets that, which is how it reads as the lever without shouting
   in a bigger typeface. The rank figure is the largest thing in the
   HUD and it glows, because the house rule is that the accent looks
   emitted and the big thing is a figure, never a headline.
 * ------------------------------------------------------------------ */

.you {
  position: fixed; z-index: 30;
  right: var(--gut); bottom: calc(var(--floor) + 42px);
  width: 316px;
  padding: 13px 15px 15px;
  border-color: var(--line);
  border-top-color: rgba(205, 183, 136, .55);
  background: var(--glass-deep);
  box-shadow: var(--lift), var(--inset), 0 0 22px -6px rgba(205, 183, 136, .22);
}
.you-head { display: flex; align-items: baseline; gap: 8px; }
.you-label {
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: var(--accent);
  opacity: .8;
}
.src {
  margin-left: auto; font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--faint);
}
.src.demo  { color: var(--warn); }
.src.stale { color: var(--bad); }

.you-rank {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 3px 9px;
  margin: 6px 0 10px;
}
#you-title {
  font-size: 25px; line-height: 1.05; color: var(--accent); letter-spacing: -.02em;
  text-shadow: 0 0 24px rgba(205, 183, 136, .40);
}
#you-served { font-size: 11.5px; }
.dim { color: var(--dim); }

.you-next {
  font-size: 12px; line-height: 1.55; color: var(--dim);
  border-top: 1px solid var(--hair); padding-top: 10px; min-height: 38px;
}
.you-next b { color: var(--ink); font-weight: 600; }

.you-row { display: flex; gap: 7px; margin-top: 11px; }
#you-addr {
  flex: 1; min-width: 0; font: 12px var(--mono); color: var(--ink);
  background: rgba(255, 255, 255, .05); border: 1px solid var(--line);
  border-radius: var(--r-ctl); padding: 8px 9px;
}
#you-addr::placeholder { color: var(--faint); }
#you-addr:focus { outline: 0; border-color: var(--accent); }
#you-check {
  font-size: 11px; letter-spacing: .06em; padding: 0 13px; border-radius: var(--r-ctl);
  background: rgba(255, 255, 255, .07); color: var(--dim);
  transition: background .2s, color .2s;
}
#you-check:hover { background: rgba(255, 255, 255, .13); color: var(--ink); }

.buy {
  display: block; margin-top: 10px; text-align: center; text-decoration: none;
  font-size: 12.5px; letter-spacing: .07em; padding: 11px 0; border-radius: var(--r-ctl);
  background: var(--accent); color: #10140a; font-weight: 600;
  box-shadow: 0 0 26px -10px rgba(205, 183, 136, .8);
  transition: filter .18s ease;
}
.buy:hover { filter: brightness(1.07); }
.buy.off {
  background: rgba(255, 255, 255, .06); color: var(--faint);
  cursor: default; box-shadow: none;
}

/* The click-a-desk inspector (#desk, .desk-*) is NOT styled here. It
   lives in panels.css, which is linked after this file and wins on
   order anyway. One owner per component: do not add a #desk rule. */

/* ------------------------------------------------------------------ *
   nav — four lowercase nouns, of two different kinds.

   Three of them open a sheet. The fourth latches a setting on the
   room. That difference has to be readable without hovering, so it is
   carried by SHAPE, not by a glyph: a door is a rectangle, a switch is
   a pill with a lamp on it. The pill and the lamp live in panels.css,
   which owns #nav .toggle.
 * ------------------------------------------------------------------ */

#nav {
  position: fixed; z-index: 30; display: flex; gap: 5px;
  left: var(--gut); bottom: calc(var(--floor) + var(--hintrow) + var(--stickspace));
}
#nav button {
  font-size: 11px; letter-spacing: .06em; padding: 7px 13px; border-radius: var(--r-ctl);
  color: var(--dim);
  transition: color .2s, border-color .2s, background .2s;
}
#nav button:hover { color: var(--accent); border-color: rgba(205, 183, 136, .34); }

/* ------------------------------------------------------------------ *
   the bottom row: the walk hint on the left, sound and X on the right.

   Both of these used to be bare text over the room: .40 white on a
   ceiling tile reads about 1.1:1, which is not a colour choice, it is
   an absence of one. They now sit on the same plate as everything
   else, just a thinner one, so they stay a line rather than a slab.
 * ------------------------------------------------------------------ */

.hint {
  position: fixed; z-index: 30; left: var(--gut); bottom: var(--floor); margin: 0;
  padding: 5px 11px; border-radius: var(--r-ctl);
  background: var(--glass-thin);
  font-size: 11.5px; letter-spacing: .04em; line-height: 1.35;
  color: var(--dim);
}
/* #hud > * turns pointer events back on for every child, and that rule
   carries an id. The hint is the one child that must stay transparent
   to the mouse: it sits over the room and it is not a control. */
#hud .hint { pointer-events: none; }

.corner {
  position: fixed; z-index: 30; right: var(--gut); bottom: var(--floor);
  display: flex; align-items: center; gap: 8px;
}
#soundbtn {
  display: flex; align-items: center; gap: 8px;
  height: 30px; padding: 0 13px; border-radius: var(--r-ctl);
  font-size: 10.5px; letter-spacing: .1em; color: var(--dim);
  transition: color .2s, border-color .2s;
}
#soundbtn:hover, #soundbtn.on { color: var(--accent); border-color: rgba(205, 183, 136, .34); }
.eq { display: flex; align-items: flex-end; gap: 2px; height: 11px; }
.eq i { display: block; width: 2px; height: 3px; background: currentColor; }
#soundbtn.on .eq i { animation: eq .9s ease-in-out infinite; }
#soundbtn.on .eq i:nth-child(2) { animation-delay: .15s; }
#soundbtn.on .eq i:nth-child(3) { animation-delay: .3s; }
#soundbtn.on .eq i:nth-child(4) { animation-delay: .45s; }
@keyframes eq { 50% { height: 11px; } }

/* the X link gets the same plate as the sound button, so the corner
   reads as one pair of controls instead of a button and a loose glyph */
.corner a {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: var(--r-ctl);
  color: var(--dim); transition: color .2s, border-color .2s;
}
.corner a:hover { color: var(--accent); border-color: rgba(205, 183, 136, .34); }
.corner a svg { width: 15px; height: 15px; }

#doorhint {
  position: fixed; z-index: 30; left: 50%; top: 50%;
  transform: translate(-50%, 46px);
  padding: 6px 16px; border-radius: var(--r-ctl);
  border-color: rgba(205, 183, 136, .3);
  font-size: 11.5px; letter-spacing: .12em; color: var(--accent);
  opacity: 0; pointer-events: none; transition: opacity .2s;
}
#doorhint.on { opacity: 1; }

/* ------------------------------------------------------------------ *
   sheets
 * ------------------------------------------------------------------ */

/* [hidden] is a UA default of display:none, and ANY author display rule
   beats it. Without this the sheet ships permanently open. */
#sheet[hidden] { display: none; }
#sheet {
  position: fixed; inset: 0; z-index: 50; display: flex;
  align-items: center; justify-content: center; padding: 20px;
  background: rgba(3, 5, 6, .72);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.sheet-card {
  width: min(560px, 100%); max-height: 82dvh; overflow: auto;
  background: #0d1011; border: 1px solid var(--line); border-radius: 6px;
  padding: 20px 22px 24px;
  box-shadow: 0 40px 90px -30px #000;
}
.sheet-head { display: flex; align-items: baseline; margin-bottom: 2px; }
#sheet-close { margin-left: auto; font-size: 10.5px; letter-spacing: .1em; color: var(--faint); }
#sheet-close:hover { color: var(--ink); }
#sheet-title { margin: 0 0 14px; font: 400 22px/1.2 var(--serif); letter-spacing: -.01em; }
#sheet-body { font: 14px/1.62 var(--serif); color: var(--dim); }
#sheet-body p { margin: 0 0 11px; }
#sheet-body b { color: var(--ink); font-weight: 600; }
#sheet-body table { width: 100%; border-collapse: collapse; margin: 4px 0 12px; font: 11.5px var(--mono); }
#sheet-body th {
  text-align: left; font-weight: 400; font-size: 9px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--faint); padding: 0 0 6px; border-bottom: 1px solid var(--line);
}
#sheet-body td { padding: 6px 0; border-bottom: 1px solid rgba(255, 255, 255, .05); color: var(--ink); }
#sheet-body .n { text-align: right; font-variant-numeric: tabular-nums; }
#sheet-body td.n { color: var(--dim); }

.pots {
  display: grid; gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: 5px; overflow: hidden; margin-bottom: 12px;
}
.pots > div { background: #0d1011; padding: 10px 12px; }
.pl { display: block; font: 9px var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.pv { display: block; font: 17px var(--mono); color: var(--accent); font-variant-numeric: tabular-nums; margin: 2px 0 3px; }
.ps { display: block; font: 10.5px/1.45 var(--mono); color: var(--dim); }

.feed { list-style: none; margin: 10px 0 0; padding: 0; font: 11px var(--mono); }
.feed li { padding: 6px 0; border-bottom: 1px solid rgba(255, 255, 255, .05); color: var(--dim); }
.k {
  display: inline-block; min-width: 66px; font-size: 9px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint);
}
.k.promoted { color: var(--accent); }
.k.resigned { color: var(--bad); }
.k.paid     { color: var(--good); }

/* the two panels that can scroll. a short window puts a bright default
   scrollbar down the edge of an otherwise dark card, so give it one. */
.sheet-card, #sheet-body { scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .18) transparent; }
.sheet-card::-webkit-scrollbar { width: 8px; }
.sheet-card::-webkit-scrollbar-track { background: transparent; }
.sheet-card::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .16); border-radius: 999px;
}
.sheet-card::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, .28);
}

/* ?bare is for the brand stills, so it has to clear EVERY overlay, not
   just #hud. The sheet and the desk inspector are siblings of it. */
.bare #hud, .bare #badge, .bare #sheet, .bare #desk { display: none !important; }

/* ------------------------------------------------------------------ *
   thumb stick — coarse pointers only. The media query that turns it on
   lives at the BOTTOM of this file, after the phone layout, because
   both write --stickspace on :root and source order decides.
 * ------------------------------------------------------------------ */

#stick {
  position: fixed; z-index: 32;
  left: var(--gut); bottom: var(--floor);
  width: 92px; height: 92px; border-radius: 50%;
  background: rgba(8, 10, 12, .40);
  backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px);
  display: none; touch-action: none;
}
#knob {
  position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: rgba(205, 183, 136, .30);
  border: 1px solid rgba(205, 183, 136, .5);
}

/* ------------------------------------------------------------------ *
   phones and narrow windows — a real layout, not a squeeze.

   Measured on the shipped build at 390x844: the HUD was eating 518 of
   844 pixels (61%) and the room was a 326px letterbox between two
   slabs. The room is the product, so the fix is structural:

     1. the lever loses its stack. The address row and the buy button
        share a line, so the panel that answers "where do I stand" is
        one block instead of five.
     2. #nav moves onto the same row as the sound and X controls, which
        were a whole row of their own for two 30px objects.
     3. the walk hint is already hidden on touch, so its band is only
        reserved when there is no thumb stick to reserve one instead.

   The bottom stack, measured up from --floor and nothing estimated:

     floor                  stick (left)          jump (right)
     + row0                 nav (left)            sound and X (right)
     + row0 + 43            the lever, full width

   where row0 is the stick band on touch and the hint band otherwise.
 * ------------------------------------------------------------------ */

@media (max-width: 720px) {
  :root { --gut: 12px; }

  .card {
    left: 50%; right: auto; transform: translateX(-50%);
    top: 12px;
    width: min(380px, calc(100% - 24px));
  }

  .chip {
    /* card top + card height + gap */
    top: calc(12px + var(--card-h) + 8px);
    right: 50%; transform: translateX(50%);
    width: min(380px, calc(100% - 24px));
  }

  /* three plates down the right edge is too much on a phone, and the
     room line is the one that repeats what the chip already says. */
  .roomline { display: none; }

  /* --- the lever, rebuilt as a grid ---------------------------------
     Two columns. Everything spans both except the last row, where the
     address input and the buy button sit side by side. That one change
     is worth 48px, which is most of what a phone has to spare. */
  .you {
    left: var(--gut); right: var(--gut); width: auto;
    bottom: calc(var(--floor) + var(--stickspace) + var(--hintrow) + 43px);
    padding: 11px 13px 13px;
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
  }
  .you-head { grid-column: 1 / -1; }
  .you-rank { grid-column: 1 / -1; margin: 5px 0 9px; }
  #you-title { font-size: 23px; }
  .you-next {
    grid-column: 1 / -1; min-height: 0;
    font-size: 11.5px; line-height: 1.45; padding-top: 9px;
  }
  .you-row { grid-column: 1; margin-top: 10px; }
  .buy {
    grid-column: 2; margin: 10px 0 0 8px;
    display: flex; align-items: center; justify-content: center;
    align-self: stretch; padding: 0 18px; white-space: nowrap;
  }

  /* --- nav and the corner controls share a row --------------------- */
  #nav,
  .corner {
    bottom: calc(var(--floor) + var(--stickspace) + var(--hintrow));
  }
  #nav { left: var(--gut); gap: 4px; }
  #nav button { padding: 8px 11px; font-size: 10.5px; }
  .corner { right: var(--gut); gap: 7px; }

  /* the word "sound" is 44px of a 366px row that has four nav nouns to
     fit. The bars are the affordance and they animate when it is on,
     and the button keeps its aria-label either way. */
  #soundbtn { font-size: 0; padding: 0 11px; }

  .hint { left: var(--gut); bottom: var(--floor); }
  #stick { left: var(--gut); }
  #doorhint { transform: translate(-50%, 34px); }

  .sheet-card { padding: 18px 16px 22px; max-height: 86dvh; }
  #sheet { padding: 12px; }
  #sheet-title { font-size: 20px; }
  .k { min-width: 58px; }
}

/* small phones. The nav row carries four nouns and the two corner
   controls, and at 320px the two of them want 328 of 296 available
   pixels. Measured, so the numbers below are the amount actually
   missing and not a guess: 8px off each button's side padding, half a
   point off the type and 1px off the gaps buys 41px, which is 1px more
   than the overlap. Tiny furniture is the house idiom anyway. */
@media (max-width: 400px) {
  #nav { gap: 3px; }
  #nav button { padding: 8px 7px; font-size: 10px; letter-spacing: .03em; }
  .corner { gap: 6px; }
  #soundbtn { padding: 0 9px; }
  /* the buy button is auto width, so at 320px it was taking 160 of the
     lever's bottom row and leaving 102 for an address field. */
  .buy { padding: 0 12px; font-size: 11.5px; letter-spacing: .04em; }
}

/* very short phones: the lever and the id card both want the screen.
   Tighten the lever and drop the hint rather than letting them meet in
   the middle. */
@media (max-height: 700px) and (max-width: 720px) {
  :root { --hintrow: 0px; }
  .you { padding: 10px 12px 11px; }
  .you-rank { margin: 4px 0 7px; }
  #you-title { font-size: 20px; }
  .you-next { padding-top: 8px; font-size: 11px; }
  .hint { display: none; }
}

/* the stick owns the bottom left on a touch device, so everything
   stacked above it has to know how tall it is. It also replaces the
   walk hint, so --hintrow goes to zero and the stack does not reserve
   a band for a line that is not drawn.

   This block is LAST on purpose. Both it and the phone block above set
   custom properties on :root, media queries add no specificity, and
   source order is therefore the whole argument. */
@media (hover: none) and (pointer: coarse) {
  /* 92 of stick plus a gap. The gap is 20 and not 12 because the sit
     hint is parked at bottom:92px by terminal.css and stands 29 tall,
     so its top edge is 121px off the bottom. Measured at 390x844 the
     nav row was clipping it by 3px; 112 puts a 5px gap between them. */
  :root { --stickspace: 112px; --hintrow: 0px; }
  #stick { display: block; }
  .hint { display: none; }
}


/* ------------------------------------------------------------------ *
   interaction states

   There were twelve hover rules, two focus, one active and one disabled in
   the whole HUD, so most controls did nothing until they were clicked. One
   system, applied everywhere: hover lifts the ink and warms the edge, active
   presses 1px and drops the ground, focus-visible draws a real ring for
   keyboard users, and disabled says so rather than looking merely quiet.
 * ------------------------------------------------------------------ */

#nav button,
#you-check,
#term-load,
#sheet-close,
#desk-close,
#copy,
#soundbtn,
/* #enter is NOT one of these any more. It was in this list from the version
   where the gate button was a small bordered control like the rest, and the
   ID selector here (1,0,0) was beating both .enter (0,1,0) and .gate > *
   (0,1,0), so the gate button kept a transition list with no opacity in it
   and snapped to full while the wordmark above it was still fading. Found by
   enumerating the rules that actually match the element, not by reading the
   file. .card-foot went with it: zero references in any html or js. */
.body {
  transition: background-color .12s ease, border-color .12s ease,
              color .12s ease, transform .06s ease, box-shadow .12s ease;
}

/* hover: never move the thing, only light it. Moving furniture under a
   pointer is what makes a HUD feel loose. */
#nav button:hover,
#you-check:hover,
#term-load:hover,
#sheet-close:hover,
#desk-close:hover {
  color: var(--ink);
  border-color: rgba(205, 183, 136, .40);
  background: rgba(205, 183, 136, .06);
}

#nav button:active,
#you-check:active,
#term-load:active,
#sheet-close:active,
#desk-close:active,
#copy:active,
#soundbtn:active {
  transform: translateY(1px);
  background: rgba(205, 183, 136, .11);
}

/* Keyboard focus gets a real ring. Pointer focus does not, or every click
   leaves a ring behind it. */
:focus { outline: none; }
#nav button:focus-visible,
#you-check:focus-visible,
#term-load:focus-visible,
#sheet-close:focus-visible,
#desk-close:focus-visible,
#copy:focus-visible,
#soundbtn:focus-visible,
#jumpbtn:focus-visible,
.body:focus-visible,
#enter:focus-visible,
a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-ctl);
}
#you-addr:focus-visible,
#term-addr:focus-visible,
#yourname:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px rgba(205, 183, 136, .16);
}

/* text inputs: a caret colour and a placeholder that is furniture */
#you-addr, #term-addr, #yourname { caret-color: var(--accent); }
#you-addr::placeholder,
#term-addr::placeholder,
#yourname::placeholder { color: var(--faint); }

/* disabled / inert: say it, do not merely whisper it */
.buy.off,
button[disabled],
a[aria-disabled="true"] {
  cursor: not-allowed;
  color: var(--faint);
  background: rgba(255, 255, 255, .04);
  border-color: var(--line);
  box-shadow: none;
}
.buy.off:hover, button[disabled]:hover { background: rgba(255, 255, 255, .04); }

/* a link with no href is not a link */
#token:not([href]) { cursor: default; }
#token[href]:hover { color: var(--accent); }

/* the body picker on the badge desk had no selected state worth the name */
.body[aria-pressed="true"], .body.on {
  border-color: rgba(205, 183, 136, .55);
  background: rgba(205, 183, 136, .09);
  color: var(--ink);
}

/* the pointer only changes over things that do something */
#stage { cursor: default; }
body.locked #stage { cursor: none; }


/* ------------------------------------------------------------------ *
   the badge desk, over the live floor
 * ------------------------------------------------------------------ */




/* The action was a 999px solid lime slab, which is the loudest object in the
   build and exactly the premium-button idiom the house style rules out. It is
   a control now: accent edge, accent text, and a fill only under the pointer. */


/* the body picker is a cosmetic choice and was carrying the visual weight of
   the mechanic. Quieter, tighter, and the selected one is the only lit row. */
.body { border-radius: var(--r-ctl); padding: 7px 9px; font-size: 11px; }
.swatch i { height: 14px; }

/* ------------------------------------------------------------------ *
   the gate, rebuilt against the reference

   No card. The scene is the point of an opening frame and a bordered panel
   parked in the middle of it hides exactly the thing it is introducing.
 * ------------------------------------------------------------------ */



.gate {
  position: absolute;
  left: clamp(22px, 5.2vw, 78px);
  bottom: clamp(30px, 7vh, 74px);
  right: clamp(22px, 5vw, 60px);
  max-width: 620px;
}

.gate-eyebrow {
  margin: 0 0 14px;
  font: 11px var(--mono);
  letter-spacing: .19em;
  text-transform: uppercase;
  color: #e8b98d;                       /* the warm band of the sky, reused */
}

.gate-mark {
  margin: 0 0 18px;
  font: 400 clamp(54px, 8.6vw, 108px)/0.92 var(--serif);
  letter-spacing: -.022em;
  color: #fbfdfb;
  text-shadow: 0 2px 40px rgba(0, 0, 0, .55);
}

.gate-copy {
  margin: 0 0 26px;
  font: 16.5px/1.62 var(--serif);
  color: rgba(240, 245, 243, .84);
  text-shadow: 0 1px 16px rgba(0, 0, 0, .6);
}

/* one light rectangle, dark text, and the key hint inside it */
.enter {
  display: inline-flex; align-items: baseline; gap: 14px;
  padding: 13px 20px;
  border: 0; border-radius: 2px;
  background: #f2f5f2;
  color: #0d1210;
  box-shadow: 0 10px 34px -16px rgba(0, 0, 0, .9);
  /* opacity has to be in this list. Without it the button was the one child
     of the gate with no opacity transition, so it snapped to full the instant
     the load-in started while the wordmark above it was still fading: the
     first thing you saw of the page was a button, on its own, over an empty
     sky. Measured off getComputedStyle, not guessed. */
  transition: background-color .13s ease, transform .07s ease,
              opacity .62s ease;
}
.enter:hover { background: #ffffff; transform: none; filter: none; }
.enter:active { transform: translateY(1px); background: #e6eae6; }
.enter-label { font: 15px var(--serif); letter-spacing: 0; }
.enter-hint {
  font: 9.5px var(--mono); letter-spacing: .2em; text-transform: uppercase;
  color: rgba(13, 18, 16, .48);
}

/* the identity picker, folded away. It is a costume choice and it was
   competing with the wordmark for the opening frame. */
.gate-id { margin-top: 22px; }
.id-toggle {
  display: inline-flex; align-items: center; gap: 7px; padding: 0;
  font: 11.5px var(--mono); color: var(--faint); background: none; border: 0;
}
.id-toggle b { color: rgba(240, 245, 243, .82); font-weight: 400; }
.id-toggle:hover { color: var(--dim); }
.id-toggle:hover b { color: var(--accent); }
.id-caret {
  width: 7px; height: 7px; margin-left: 2px;
  border-right: 1.4px solid currentColor; border-bottom: 1.4px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform .16s ease;
}
#badge.id-open .id-caret { transform: rotate(-135deg) translate(-2px, -2px); }

.id-body { margin-top: 16px; max-width: 430px; }
.id-body[hidden] { display: none; }
.id-body .field { margin-bottom: 14px; }
.id-body #yourname { background: rgba(255, 255, 255, .07); }

@media (max-width: 720px) {
  .gate { left: 18px; right: 18px; bottom: 26px; }
  .gate-mark { font-size: clamp(44px, 15vw, 68px); margin-bottom: 14px; }
  .gate-copy { font-size: 15px; margin-bottom: 20px; }
  .gate-copy br { display: none; }
}

/* ------------------------------------------------------------------ *
   the load-in

   The scene takes a moment to build: eleven storeys of generated facade, a
   dusk sky, and a 64m floor with a hundred desks on it. Before this the
   page was black for that whole moment and then everything arrived at
   once, which is the least cinematic thing a cinematic opening can do.
 * ------------------------------------------------------------------ */

/* The gate always opens on the street, and the street's sky is a known
   gradient, so paint it in CSS on the very first frame. The canvas then
   fades in over a background that already matches it and there is never a
   black rectangle. Stops match app/textures.js duskTexture. */
body {
  background: linear-gradient(to bottom,
    #060c1e 0%, #0e2348 26%, #20486a 48%, #3f6b7d 64%,
    #7d8480 74%, #bb8f72 84%, #dda274 93%, #c17f4e 100%);
}

#stage {
  opacity: 0;
  transition: opacity .85s ease .05s;
}
body.ready #stage { opacity: 1; }

/* the type arrives a beat behind the room, and each line a beat behind the
   one above it. 1.5s end to end: long enough to read as a title card, short
   enough that nobody is waiting on it. */
.gate > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .62s ease, transform .62s cubic-bezier(.22, .8, .3, 1);
}
body.ready .gate > * { opacity: 1; transform: none; }
body.ready .gate-eyebrow { transition-delay: .30s; }
body.ready .gate-mark    { transition-delay: .42s; }
body.ready .gate-copy    { transition-delay: .62s; }
body.ready .enter        { transition-delay: .80s; }
body.ready .gate-id      { transition-delay: .95s; }

/* Anyone who has asked not to be animated at gets the finished state
   immediately rather than a slower version of the same thing. */
@media (prefers-reduced-motion: reduce) {
  #stage, .gate > * { transition: none; opacity: 1; transform: none; }
}

/* The crosshair. styles.css already hides the cursor under body.locked and
   nothing replaced it, so the one mode where aiming matters had nothing to
   aim with. Small, dim, and the accent, so it reads as the same system as
   the desk cue it selects. */
body.locked #stage { cursor: none; }
body.locked::after {
  content: "";
  position: fixed; left: 50%; top: 50%;
  width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--accent);
  opacity: .5;
  pointer-events: none;
  z-index: 40;
}

/* Arrival and architectural wayfinding. The building remains the hero. */
#badge[hidden] { display:none; }
.arrival-mast { position:absolute;inset:27px 36px auto;display:flex;justify-content:space-between;gap:20px;font:10px var(--mono);letter-spacing:.16em;color:#d8e1e5; }
.arrival-mast i { font-style:normal;opacity:.4;padding:0 13px; }
.arrival-seal { position:absolute;right:5vw;bottom:8vh;display:flex;flex-direction:column;align-items:center;color:#d4b997;border-top:1px solid #d4b99755;padding:15px 8px 0; }
.arrival-seal span { font:9px var(--mono);letter-spacing:.18em; }
.arrival-seal b { font:400 86px/.95 var(--serif);margin:10px 0 14px; }
.gate-copy { max-width:440px; }
.enter { min-width:212px;justify-content:space-between; }
.enter-hint { font-size:12px;letter-spacing:.05em; }
.floor-wayfinding { position:fixed;left:50%;top:20px;transform:translateX(-50%);z-index:25;display:flex;align-items:center;gap:12px;padding:9px 14px;border:1px solid var(--line);background:var(--glass);border-radius:3px; }
.way-no { font:24px var(--serif);color:#d6c5a5;padding-right:12px;border-right:1px solid var(--line); }
.floor-wayfinding b { display:block;font:11px var(--mono);color:var(--ink); }
.floor-wayfinding div>span { display:block;font:9px var(--mono);color:var(--dim);margin-top:4px; }
#sit-action { margin-left:12px;font:10px var(--mono);padding:8px 10px;color:var(--accent);border-left:1px solid var(--line);white-space:nowrap; }
kbd { font:9px var(--mono);border:1px solid var(--line);padding:2px 4px;margin-left:7px;color:var(--dim); }
body.seated .floor-wayfinding { visibility:hidden; }
body:has(#badge:not(.gone)) #hud { visibility:hidden; }
@media(max-width:1250px){.floor-wayfinding{top:100px;left:20px;transform:none}.floor-wayfinding div>span{display:none}}
@media(max-width:720px){
 .arrival-mast{inset:20px 18px auto;font-size:8px;letter-spacing:.07em}
 .arrival-seal{right:20px;top:70px;bottom:auto;padding-top:8px}.arrival-seal b{font-size:49px;margin:5px 0}.arrival-seal span:last-child{display:none}
 .gate{bottom:max(26px,env(safe-area-inset-bottom));max-height:calc(100svh - 140px);overflow:auto;padding-top:12px}
 .gate-mark{font-size:clamp(56px,18vw,78px)}
 .floor-wayfinding{top:126px;left:var(--gut);right:var(--gut);padding:7px 10px;gap:8px}
 .floor-wayfinding #sit-action{margin-left:auto;font-size:9px}.way-no{font-size:19px}
}
@media(max-height:600px) and (min-width:721px){.gate{bottom:22px}.gate-mark{font-size:62px}.gate-copy{margin-bottom:14px}.gate-id{margin-top:13px}.arrival-seal{bottom:30px}}

.floor-target[hidden]{display:none}.floor-target{position:fixed;z-index:24;bottom:30px;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:14px;padding:10px 15px;border:1px solid #cdb78845;border-radius:3px;background:var(--glass-deep);pointer-events:none}
.target-arrow{color:var(--accent);font:26px var(--serif);line-height:1;display:block}.floor-target div{display:flex;flex-direction:column;gap:5px}.floor-target div span{font:9px var(--mono);color:var(--dim)}.floor-target b{font:10px var(--mono);font-weight:400;color:var(--accent)}
body.seated .floor-target{visibility:hidden}
@media(max-width:720px){.floor-target{top:180px;bottom:auto;left:var(--gut);transform:none;padding:8px 11px}.target-arrow{font-size:20px}}

#lift-transit[hidden]{display:none}#lift-transit{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:51;pointer-events:none;opacity:0;color:#d7c4a4}
#lift-transit>span{font:10px var(--mono);letter-spacing:.3em}#lift-transit>b{font:96px/1 var(--serif);font-weight:400;margin:18px 0}#lift-transit i{font:30px var(--mono);vertical-align:middle;color:var(--accent)}#lift-transit p{font:12px var(--mono);letter-spacing:.12em;margin:0}

/* A phone gets one identity card and one location row. Keep the centre
   of the view for the office, with control guidance beside the thumbs. */
#touch-hint { display:none; }
@media(max-width:720px) {
  #room-chip { display:none; }
  .floor-wayfinding { top:85px; }
  .floor-target { top:140px; }
}
@media(hover:none) and (pointer:coarse) {
  #sit-action kbd { display:none; }
  #touch-hint { display:block;position:fixed;left:115px;right:85px;bottom:calc(var(--floor) + 24px);margin:0;text-align:center;font:9px/1.5 var(--mono);color:#bbc3bd;pointer-events:none; }
  #stick::after { content:"move";position:absolute;bottom:5px;left:0;right:0;text-align:center;font:8px var(--mono);color:#bbc3bd;pointer-events:none; }
}

/* Loxley Partners: a quieter brass identity on the trading floor. */
.gate-mark{font-size:clamp(68px,7.6vw,108px);line-height:.88;letter-spacing:-.045em}.gate-mark span{display:block;font-size:.40em;letter-spacing:.17em;text-transform:uppercase;margin:18px 0 24px 4px}.gate-eyebrow{color:#cdb788}.arrival-mast{letter-spacing:.11em}.pfp{color:#cdb788;background:#142c24;border-color:#5a6550}
@media(max-width:720px){.gate-mark{font-size:70px}.gate-mark span{font-size:27px;margin:14px 0 22px 3px}.arrival-mast{font-size:7px;letter-spacing:.035em}}
