/* ui.css — the shared UI kit.
 *
 * Ten primitives carry the whole client's chrome; every view composes them and
 * none of them knows what a building, a tech or a sector is. Built from the
 * `--u-*` tokens in tokens.css, mirrored one-for-one by the builders in
 * js/views/ui.js, and shown in every state on /ui-kit.html — which is the page
 * to open when changing anything here.
 *
 * Two rules this file exists to enforce (UI-REDESIGN.md §1.4):
 *   · nothing truncates. Chips, pills and plates wrap; no `text-overflow`
 *     lives in this file, and none belongs in a view either.
 *   · z-index comes from the ladder in tokens.css, never from a local guess.
 */

/* ══ 1. Corner-bracket frame ══════════════════════
   The signature motif: four cyan L-brackets floating just outside a panel's
   corners. Two arms come from the host's own pseudo-elements and two from the
   `<span class="u-brk-c">` the builders emit, so a bracketed panel costs one
   inert child and no wrapper. */
.u-brk{position:relative}
.u-brk::before,
.u-brk::after,
.u-brk>.u-brk-c::before,
.u-brk>.u-brk-c::after{
  content:'';position:absolute;
  width:var(--u-brk);height:var(--u-brk);
  border:var(--u-brk-w) solid var(--u-line);
  pointer-events:none;
}
.u-brk>.u-brk-c{position:absolute;inset:0;pointer-events:none}
.u-brk::before               {top:calc(-1*var(--u-brk-o));   left:calc(-1*var(--u-brk-o));  border-right:0;border-bottom:0}
.u-brk::after                {top:calc(-1*var(--u-brk-o));   right:calc(-1*var(--u-brk-o)); border-left:0; border-bottom:0}
.u-brk>.u-brk-c::before      {bottom:calc(-1*var(--u-brk-o));left:calc(-1*var(--u-brk-o));  border-right:0;border-top:0}
.u-brk>.u-brk-c::after       {bottom:calc(-1*var(--u-brk-o));right:calc(-1*var(--u-brk-o)); border-left:0; border-top:0}
/* Tight variant for small panels, where the full arm would out-measure the box. */
.u-brk.is-tight{--u-brk:11px;--u-brk-o:4px;--u-brk-w:2px}

/* ══ 2. HUD chip ══════════════════════════════════
   Label + value, boxed. The whole top rail is these, and the readability the
   Unity build gets over the old 11px mono topbar is mostly this one rule. */
.u-chip{
  display:inline-flex;align-items:center;gap:8px;
  min-height:var(--u-chip-h);padding:0 12px;
  border:1px solid var(--u-line-dim);border-radius:var(--u-r-sm);
  background:var(--u-glass);
}
.u-chip-l{
  font:600 11px/1 var(--u-font-ui);letter-spacing:.12em;text-transform:uppercase;
  color:var(--u-label);white-space:nowrap;
}
.u-chip-v{
  font:700 16px/1 var(--u-font-ui);font-variant-numeric:tabular-nums;
  color:var(--u-value);white-space:nowrap;
}
.u-chip.is-gold{border-color:rgba(255,200,68,.55)}
.u-chip.is-gold .u-chip-v{color:var(--gold)}
.u-chip.is-warn{border-color:rgba(255,34,68,.5)}
.u-chip.is-warn .u-chip-v{color:var(--u-bad)}
/* Scrap reads rusty (unrefined), metal reads steel, silicon ore a dusky violet
   and refined silicon a bright lilac, meals read grown-green — the set a
   label-less rail would otherwise render as identical numbers. */
.u-chip.is-scrap .u-chip-v{color:var(--u-scrap)}
.u-chip.is-metal .u-chip-v{color:var(--u-metal)}
.u-chip.is-silicon-ore .u-chip-v{color:var(--u-silicon-ore)}
.u-chip.is-silicon .u-chip-v{color:var(--u-silicon)}
.u-chip.is-meal  .u-chip-v{color:var(--u-meal)}
.u-chip.is-clickable{cursor:pointer;transition:border-color .15s,box-shadow .15s}
.u-chip.is-clickable:hover{border-color:var(--u-line);box-shadow:0 0 12px rgba(79,216,255,.2)}
/* A value that just changed flashes rather than counting up — a count-up would
   render numbers the server never sent. */
/* No `to` frame on purpose: the animation resolves back to whatever colour the
   element itself specifies, so a gold chip flashes back to gold. */
@keyframes uFlash{from{color:var(--u-line)}}
.u-chip-v.is-fresh{animation:uFlash .2s ease-out}
/* Progress under a chip's value (the XP chip). Fill width is set inline from
   the server's own numbers. */
.u-chip-bar{width:56px;height:4px;border-radius:2px;background:rgba(79,216,255,.14);overflow:hidden}
.u-chip-bar>span{display:block;height:100%;background:linear-gradient(90deg,var(--u-cta-b),var(--u-cta-a))}

/* ══ 3. Dialog ════════════════════════════════════
   Title + LV sub + close, a rule, description, stat chips, actions. The
   building panels are this; so is the battle result overlay. */
.u-dlg{
  position:relative;z-index:var(--z-panel);
  width:min(560px,92vw);padding:18px 20px 20px;
  border:1px solid var(--u-line-dim);border-radius:var(--u-r);
  background:var(--u-glass);
  box-shadow:0 18px 44px rgba(0,0,0,.62),0 0 26px rgba(40,120,200,.18),inset 0 1px 0 rgba(255,255,255,.05);
  animation:uRise .12s ease-out;
}
@keyframes uRise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.u-dlg-head{display:flex;align-items:flex-start;gap:14px}
/* Optional glyph beside the title — the host colours it (currentColor). */
.u-dlg-icon{flex:0 0 auto;width:38px;height:38px;display:grid;place-items:center}
.u-dlg-icon svg{width:32px;height:32px;filter:drop-shadow(0 0 3px currentColor)}
.u-dlg-titles{flex:1;min-width:0}
.u-dlg-title{
  font:700 24px/1.15 var(--u-font-ui);letter-spacing:.01em;color:var(--u-value);
  overflow-wrap:anywhere;
}
.u-dlg-sub{
  margin-top:5px;
  font:600 12px/1 var(--u-font-ui);letter-spacing:.16em;text-transform:uppercase;
  color:var(--u-line);
}
.u-dlg-x{
  flex:0 0 auto;width:30px;height:30px;
  display:grid;place-items:center;
  background:none;border:0;border-radius:var(--u-r-sm);
  color:var(--u-line);font-size:19px;line-height:1;cursor:pointer;
  transition:background .15s,color .15s;
}
.u-dlg-x:hover{background:rgba(79,216,255,.14);color:#fff}
.u-rule{height:1px;background:var(--u-line-dim);margin:13px 0}
.u-dlg-desc{font:400 15px/1.5 var(--u-font-ui);color:var(--u-body);overflow-wrap:anywhere}
.u-chips{display:flex;flex-wrap:wrap;gap:8px}
.u-dlg-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:13px}
.u-dlg-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:15px}

/* ══ 4. Primary CTA + cost note ═══════════════════
   One saturated fill per panel, with the corner notched off. The cost always
   sits *beside* the button so a long cost line can never squeeze the label. */
.u-cta{
  font:700 15px/1 var(--u-font-ui);letter-spacing:.18em;text-transform:uppercase;
  color:var(--u-cta-ink);
  background:linear-gradient(135deg,var(--u-cta-a),var(--u-cta-b));
  border:0;padding:13px 26px;cursor:pointer;
  clip-path:polygon(0 0,100% 0,100% calc(100% - 11px),calc(100% - 11px) 100%,0 100%);
  filter:drop-shadow(3px 3px 0 rgba(0,0,0,.5));
  transition:filter .15s,opacity .15s;
}
.u-cta:hover:not(:disabled){filter:drop-shadow(3px 3px 0 rgba(0,0,0,.5)) brightness(1.12)}
.u-cta:disabled{opacity:.4;cursor:not-allowed;filter:grayscale(.6)}
.u-cta.is-sm{font-size:12px;padding:9px 16px;letter-spacing:.14em}
.u-cta.is-ok{background:linear-gradient(135deg,#3ce88f,#12a05a)}
/* Meals are grown, so the control that spends one reads the same green as the
   Hydroponics bay and the rail's MEALS chip. */
.u-cta.is-meal{background:linear-gradient(135deg,#a9f07f,#5ab63c)}
.u-cta.is-bad{background:linear-gradient(135deg,#ff6a86,#c31133);color:#fff}
/* Ghost action: same geometry, no fill — for the secondary of a pair. */
.u-cta.is-ghost{
  background:none;border:1px solid var(--u-line-dim);color:var(--u-line);
  filter:none;clip-path:none;border-radius:var(--u-r-sm);
}
.u-cta.is-ghost:hover:not(:disabled){border-color:var(--u-line);background:rgba(79,216,255,.1);filter:none}
.u-cost{
  font:600 13px/1.35 var(--u-font-ui);color:var(--u-cost);
  letter-spacing:.03em;overflow-wrap:anywhere;
}
/* A cost the player cannot currently pay. */
.u-cost.is-short{color:#ff9aae}
.u-cost+.u-cost{margin-left:8px}

/* ── Meter ────────────────────────────────────────
   One progress bar for the whole client: build and research timers, craft
   jobs, pilot attribute XP. */
.u-meter{display:block;height:6px;border-radius:3px;background:rgba(79,216,255,.14);overflow:hidden}
.u-meter>span{display:block;height:100%;background:linear-gradient(90deg,var(--u-cta-b),var(--u-cta-a));transition:width .3s}
.u-meter.is-train>span{background:linear-gradient(90deg,#c14d8c,var(--u-train))}
.u-meter.is-cap>span{background:linear-gradient(90deg,#7a5a1a,#d4b46a)}
.u-meter.is-ok>span{background:linear-gradient(90deg,#12a05a,#3ce88f)}
.u-meter.is-bad>span{background:linear-gradient(90deg,#c31133,#ff6a86)}
/* A mining drone's hold filling, in the palette of the ore it carries. */
.u-meter.is-scrap>span{background:linear-gradient(90deg,#8a4f22,var(--u-scrap))}
.u-meter.is-silicon-ore>span{background:linear-gradient(90deg,#4f3f86,var(--u-silicon-ore))}
/* A star-base store filling, in the palette of what it holds. */
.u-meter.is-metal>span{background:linear-gradient(90deg,#5b6672,var(--u-metal))}
.u-meter.is-silicon>span{background:linear-gradient(90deg,#6f5cc0,var(--u-silicon))}
.u-meter.is-meal>span{background:linear-gradient(90deg,#4c8a30,var(--u-meal))}
/* Why an action is unavailable. Never a tooltip: a blocked button states its
   reason in place. */
.u-blocked{
  font:400 12px/1.4 var(--u-font-ui);color:#ff9aae;
  display:flex;align-items:flex-start;gap:6px;margin-top:9px;
}
.u-blocked::before{content:'!';flex:0 0 auto;font-weight:700;color:var(--u-bad)}

/* ══ 5. Stat chip ═════════════════════════════════
   The label / value atom, boxed. Wraps to two rows before it ever clips, and
   carries an optional delta line for "what the next level buys". */
.u-stat{
  display:flex;flex-direction:column;gap:3px;
  padding:7px 11px;min-width:0;
  border:1px solid var(--u-line-soft);border-radius:var(--u-r-sm);
  background:var(--u-well);
}
.u-stat-l{
  font:600 10px/1.2 var(--u-font-ui);letter-spacing:.13em;text-transform:uppercase;
  color:var(--u-label);
}
.u-stat-v{
  font:700 14px/1.25 var(--u-font-ui);font-variant-numeric:tabular-nums;
  color:var(--u-value);overflow-wrap:anywhere;
}
.u-stat-d{font:600 11px/1.2 var(--u-font-ui);color:var(--u-cost)}
.u-stat.is-warn{border-color:rgba(255,34,68,.4)}
.u-stat.is-warn .u-stat-v{color:#ffb3c0}
.u-stat.is-ok .u-stat-v{color:var(--u-ok)}

/* ══ 6. Status pill ═══════════════════════════════
   The state of a list row, stated as a word. */
.u-pill{
  display:inline-flex;align-items:center;gap:6px;
  padding:7px 14px;border-radius:var(--u-r-sm);
  border:1px solid var(--u-idle);background:rgba(8,18,38,.6);
  font:700 12px/1 var(--u-font-ui);letter-spacing:.13em;text-transform:uppercase;
  color:var(--u-idle);white-space:nowrap;
}
.u-pill.is-done{border-color:var(--u-ok);color:var(--u-ok);background:rgba(0,232,122,.09)}
.u-pill.is-active{border-color:var(--u-line);color:var(--u-line);background:rgba(79,216,255,.12)}
.u-pill.is-warn{border-color:var(--u-warn);color:var(--u-warn);background:rgba(255,200,68,.1)}
.u-pill.is-bad{border-color:var(--u-bad);color:#ff9aae;background:rgba(255,34,68,.09)}
/* For a tile or a seat head, where the full pill would out-measure its host. */
.u-pill.is-sm{font-size:10px;letter-spacing:.1em;padding:4px 8px;gap:4px}
.u-pill.is-locked{opacity:.55}

/* ══ 7. Module pin ════════════════════════════════
   A round badge over a station module: ring colour is the state, glyph is what
   wants attention. When its module pans off-screen the pin docks to the
   viewport edge (`.is-docked`) and clicking it pans back to the module — with a
   camera that only pans, the docked pins are the station's minimap. */
.u-pin-layer{position:absolute;inset:0;z-index:var(--z-pins);pointer-events:none;overflow:hidden}
.u-pin{
  position:absolute;transform:translate(-50%,-50%);
  width:var(--u-pin);height:var(--u-pin);border-radius:50%;
  display:grid;place-items:center;
  border:2px solid var(--u-idle);
  background:radial-gradient(circle at 50% 35%,rgba(24,48,84,.95),rgba(3,9,20,.96));
  color:var(--u-idle);cursor:pointer;pointer-events:auto;
  box-shadow:0 0 12px rgba(0,0,0,.55);
  transition:transform .12s,box-shadow .15s;
}
.u-pin:hover{transform:translate(-50%,-50%) scale(1.08)}
.u-pin svg,.u-pin .u-pin-glyph{width:22px;height:22px;font-size:18px;line-height:1}
.u-pin.is-idle {border-color:var(--u-line);   color:var(--u-line)}
.u-pin.is-busy {border-color:var(--u-warn);   color:var(--u-warn)}
.u-pin.is-alert{border-color:var(--u-bad);    color:#ff8ea0}
.u-pin.is-build{border-style:dashed;border-color:var(--u-line);color:var(--u-line)}
.u-pin.is-ready{border-color:var(--u-ok);color:var(--u-ok);animation:uPinPulse 1.6s ease-in-out infinite}
@keyframes uPinPulse{0%,100%{box-shadow:0 0 8px rgba(0,232,122,.35)}50%{box-shadow:0 0 18px rgba(0,232,122,.7)}}
/* Subtitle plate under a pin — one line of live state (170/180 · 4m 12s). */
.u-pin-sub{
  position:absolute;top:calc(50% + var(--u-pin)/2 + 5px);left:50%;transform:translateX(-50%);
  padding:2px 7px;border-radius:3px;white-space:nowrap;
  background:rgba(3,9,20,.82);border:1px solid var(--u-line-soft);
  font:600 10px/1.3 var(--u-font-ui);letter-spacing:.06em;color:var(--u-body);
}
/* Docked to the viewport edge, with a caret pointing the way home. */
.u-pin.is-docked{box-shadow:0 0 14px rgba(0,0,0,.7)}
.u-pin.is-docked::after{
  content:'';position:absolute;width:0;height:0;
  border:5px solid transparent;
}
.u-pin.is-docked[data-edge="left"]::after {right:100%;margin-right:2px;border-right-color:currentColor}
.u-pin.is-docked[data-edge="right"]::after{left:100%; margin-left:2px; border-left-color:currentColor}
.u-pin.is-docked[data-edge="top"]::after  {bottom:100%;margin-bottom:2px;border-bottom-color:currentColor}
.u-pin.is-docked[data-edge="bottom"]::after{top:100%;margin-top:2px;border-top-color:currentColor}

/* ══ Job banner ═══════════════════════════════════
   The one in-flight job a screen can have. Only the fill's width and the eta's
   text change between ticks, and only `patchJob` changes them. */
.u-job{
  display:flex;flex-direction:column;gap:9px;
  padding:11px 13px;
  border:1px solid var(--u-line-dim);border-radius:var(--u-r-sm);
  background:var(--u-well);
}
.u-job-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px}
.u-job-info{flex:1 1 130px;min-width:0;display:flex;flex-direction:column;gap:3px}
.u-job-name{font:600 15px/1.25 var(--u-font-ui);color:var(--u-value);overflow-wrap:anywhere}
.u-job-eta{
  font:600 12px/1.3 var(--u-font-ui);font-variant-numeric:tabular-nums;
  color:var(--u-line);letter-spacing:.04em;
}

/* ══ Empty state ══════════════════════════════════ */
.u-empty{
  display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:26px 16px;text-align:center;
}

/* ══ 8. Bay overlay ═══════════════════════════════
   A near-full-bleed bracketed panel: header strip, a left context column, a
   right list grouped by tier. The Fabricator, Research and Training layers are
   all this one shape. */
.u-bay{
  /* Inset by the bracket offset so the corner brackets have room to sit outside
     the panel without being clipped by the stage. */
  position:absolute;inset:calc(var(--u-brk-o) + 3px);z-index:var(--z-bay);
  display:flex;flex-direction:column;
  padding:22px 26px 24px;
  border:1px solid var(--u-line-dim);border-radius:var(--u-r);
  background:var(--u-glass);
  box-shadow:0 24px 60px rgba(0,0,0,.65);
  animation:uRise .12s ease-out;
}
.u-bay-head{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}
.u-bay-head-actions{display:flex;align-items:center;gap:10px;margin-left:auto}
.u-bay-body{flex:1;min-height:0;display:flex;gap:22px;margin-top:14px}
.u-bay-side{
  flex:0 0 300px;min-width:0;display:flex;flex-direction:column;gap:10px;
  overflow-y:auto;
}
.u-bay-list{flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;overflow-y:auto;padding-right:6px}
.u-group-label{
  font:700 12px/1 var(--u-font-ui);letter-spacing:.18em;text-transform:uppercase;
  color:var(--u-label);margin-bottom:9px;
}
/* A group label with an action beside it (an Output group's Collect). */
.u-group-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 16px;margin-bottom:9px}
.u-group-head>.u-group-label{margin-bottom:0}
/* One row of a bay list: name, a meta line of facts, a state pill. */
.u-row{
  display:flex;align-items:center;gap:14px;
  padding:11px 14px;
  border:1px solid var(--u-line-soft);border-radius:var(--u-r-sm);
  background:var(--u-well);
}
.u-row+.u-row{margin-top:8px}
.u-row.has-body{align-items:flex-start}
.u-row-icon{flex:0 0 38px;width:38px;height:38px;color:var(--u-line);display:grid;place-items:center}
.u-row-icon svg{width:32px;height:32px}
.u-row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.u-row-body{display:flex;flex-direction:column;gap:7px;margin-top:3px}
.u-row-name{font:600 17px/1.2 var(--u-font-ui);color:var(--u-value);overflow-wrap:anywhere}
.u-row-meta{font:400 13px/1.4 var(--u-font-ui);color:var(--u-label);overflow-wrap:anywhere}
.u-row-side{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:6px}
.u-row.is-done{border-color:rgba(0,232,122,.28)}
.u-row.is-bad{border-color:rgba(255,34,68,.26)}
.u-row.is-locked{opacity:.62}

/* ══ 9. Hex map node ══════════════════════════════
   A sector on the galactic projection: hexagon, glow by state, name plate
   under it. The hexagon is two clipped layers because clip-path drops borders —
   the outer one *is* the border. */
.u-hex{position:relative;display:flex;flex-direction:column;align-items:center;gap:9px;cursor:pointer}
.u-hex-shape{
  /* Sized from tokens so a host that has to fit N of these in a fixed height
     (the galactic projection) can shrink them without re-authoring the
     primitive. The breakpoints below set the defaults. */
  position:relative;width:var(--u-hex-w);height:var(--u-hex-h);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  background:var(--u-line-dim);
  filter:drop-shadow(0 0 14px rgba(79,216,255,.28));
  transition:filter .18s;
}
.u-hex-fill{
  position:absolute;inset:3px;
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
  background:radial-gradient(circle at 50% 45%,#132a4c,#050c1c 72%);
  display:grid;place-items:center;overflow:hidden;
}
.u-hex:hover .u-hex-shape{filter:drop-shadow(0 0 22px rgba(79,216,255,.55))}
.u-hex.is-cleared .u-hex-shape{background:var(--u-line)}
.u-hex.is-locked  .u-hex-shape{background:rgba(95,134,168,.5);filter:none}
.u-hex.is-locked  {opacity:.72}
.u-hex-plate{
  padding:6px 12px;text-align:center;
  border:1px solid var(--u-line-dim);border-radius:var(--u-r-sm);
  background:var(--u-glass-flat);
}
.u-hex-name{font:700 14px/1.2 var(--u-font-ui);letter-spacing:.1em;text-transform:uppercase;color:var(--u-value)}
.u-hex-meta{margin-top:2px;font:600 12px/1.2 var(--u-font-ui);letter-spacing:.06em;color:var(--u-label)}
.u-hex.is-cleared .u-hex-meta{color:var(--u-ok)}
.u-hex.is-open    .u-hex-meta{color:var(--u-line)}
/* The cleared tick, pinned to the hexagon's upper-right shoulder. It sits
   outside `.u-hex-shape` because a clip-path clips its own children. */
.u-hex-badge{
  position:absolute;top:-6px;right:4px;z-index:1;
  width:28px;height:28px;border-radius:50%;
  display:grid;place-items:center;
  background:var(--u-ok);color:#04220f;font:700 15px/1 var(--u-font-ui);
  box-shadow:0 0 12px rgba(0,232,122,.5);
}

/* ══ 10. Header strip ═════════════════════════════
   The bar over a full-screen activity: back, title, a counter chip, close. */
.u-strip{
  display:flex;align-items:center;gap:14px;
  height:56px;padding:0 16px;
  border-bottom:1px solid var(--u-line-dim);
  background:rgba(5,12,26,.94);
}
.u-strip-back{
  width:56px;align-self:stretch;flex:0 0 auto;margin-left:-16px;
  display:grid;place-items:center;
  background:rgba(30,58,102,.55);border:0;border-right:1px solid var(--u-line-soft);
  color:var(--u-line);font-size:20px;line-height:1;cursor:pointer;
}
.u-strip-back:hover{background:rgba(40,84,140,.7)}
.u-strip-title{
  font:700 19px/1 var(--u-font-display);letter-spacing:.16em;text-transform:uppercase;
  color:var(--u-value);
}
.u-strip-spacer{flex:1}
.u-strip-chip{
  display:inline-flex;align-items:center;gap:8px;padding:9px 15px;
  border:1px solid var(--u-line-dim);border-radius:var(--u-r-sm);background:var(--u-glass);
  font:700 13px/1 var(--u-font-ui);letter-spacing:.12em;color:var(--u-line);white-space:nowrap;
}

/* ══ Shared bits ══════════════════════════════════ */
/* Section label above a column or group. */
.u-label{font:700 11px/1 var(--u-font-ui);letter-spacing:.18em;text-transform:uppercase;color:var(--u-label)}
.u-note{font:400 13px/1.45 var(--u-font-ui);color:var(--u-mute)}
.u-mono{font-family:var(--u-font-mono)}
/* Slim cyan scrollbar — the kit's own scroll containers opt in. */
.u-bay-side,.u-bay-list,.u-scroll{scrollbar-width:thin;scrollbar-color:rgba(79,216,255,.45) transparent}
.u-bay-side::-webkit-scrollbar,.u-bay-list::-webkit-scrollbar,.u-scroll::-webkit-scrollbar{width:8px}
.u-bay-side::-webkit-scrollbar-thumb,.u-bay-list::-webkit-scrollbar-thumb,.u-scroll::-webkit-scrollbar-thumb{
  background:rgba(79,216,255,.4);border-radius:4px;
}
.u-bay-side::-webkit-scrollbar-track,.u-bay-list::-webkit-scrollbar-track,.u-scroll::-webkit-scrollbar-track{background:transparent}

/* ══ Reflow ═══════════════════════════════════════
   Three breakpoints, three different jobs (UI-REDESIGN.md §4 Phase 7):
   `max-width` collapses columns, `max-height` is the landscape phone and
   shrinks vertical chrome, `pointer: coarse` grows what a finger has to hit. */

/* Narrow: columns collapse. */
@media (max-width:900px){
  .u-bay{padding:16px}
  .u-dlg{width:min(560px,96vw);padding:15px 16px 17px}
  .u-dlg-title{font-size:21px}
  :root{--u-hex-w:118px;--u-hex-h:104px}
  .u-bay-side{flex-basis:240px}
}

/* Narrow *and* tall — a phone held upright, or a small window. Only here does
   stacking the bay's two columns help; on a short screen it halves what is
   already the scarcest axis. */
@media (max-width:900px) and (min-height:521px){
  .u-bay-body{flex-direction:column;gap:14px;overflow-y:auto}
  .u-bay-side{flex:0 0 auto;overflow:visible}
  .u-bay-list{overflow:visible}
}

/* Short: the landscape phone. Vertical chrome tightens and anything tall
   scrolls inside itself instead of pushing the stage off-screen. */
@media (max-height:520px){
  .u-bay{padding:12px 14px}
  .u-bay-body{gap:14px;margin-top:10px}
  .u-bay-side{flex-basis:210px}
  .u-dlg{
    padding:13px 15px 15px;
    /* The level ladder and a long description must not push a dialog past the
       viewport: it scrolls inside itself instead. */
    max-height:calc(100dvh - 96px);overflow-y:auto;
  }
  .u-dlg-title{font-size:19px}
  .u-dlg-desc{font-size:13px;line-height:1.4}
  .u-rule{margin:9px 0}
  .u-dlg-chips,.u-chips{gap:6px;margin-top:9px}
  .u-dlg-actions{gap:9px;margin-top:11px}
  .u-stat{padding:6px 9px}
  .u-stat-v{font-size:13px}
  .u-row{padding:9px 11px}
  .u-row-name{font-size:15px}
  .u-strip{height:48px}
  .u-strip-back{width:48px}
  .u-strip-title{font-size:16px;letter-spacing:.12em}
  :root{--u-hex-w:104px;--u-hex-h:92px}
  .u-hex-name{font-size:12px}
  .u-hex-meta{font-size:11px}
  .u-hex{gap:7px}
  .u-hex-plate{padding:5px 9px}
  .u-empty{padding:16px 12px}
}

/* The 640×320 floor: two sectors in a tier plus their name plates do not fit
   the remaining height at the 104px step, so the hexagon takes one more. */
@media (max-height:400px){
  :root{--u-hex-w:88px;--u-hex-h:78px}
  .u-hex-name{font-size:11px;letter-spacing:.08em}
  .u-hex-meta{font-size:10px}
  .u-hex-badge{width:22px;height:22px;font-size:12px}
}

/* Touch: hit areas a finger can land on, and an `:active` for the feedback a
   hover state used to carry. */
@media (pointer: coarse){
  .u-pin{width:48px;height:48px}
  .u-pin:active{transform:translate(-50%,-50%) scale(.94)}
  .u-cta:active:not(:disabled){filter:drop-shadow(3px 3px 0 rgba(0,0,0,.5)) brightness(1.18)}
  .u-row:active{border-color:var(--u-line-dim)}
  .u-hex:active .u-hex-shape{filter:drop-shadow(0 0 22px rgba(79,216,255,.55))}
  .u-dlg-x{width:44px;height:44px}
}
