/* hub.css — THE PLAYER HUB (the utility panel on the website).
   =========================================================================
   A PAGE SHEET LAYS OUT ITS PAGE; IT DOES NOT DESCRIBE A SURFACE. Every
   record on this page (.hub-plate, .hub-tile, .hub-gauge, .hub-slot,
   .hub-item, .hub-stat, ...) is named in terminal.css section 6b, THE
   SURFACE REGISTER, and takes the house grammar from there. Chips are the
   house .pill, small buttons the house .btn-sm, the hero name the house
   .page-h1, interior headings the --tm-h-* steps, radii the --r tokens. A
   site theme (hatch) re-rounds these names in its own sheet.

   THE SHAPE (owner, 2026-08-23: "reads like a paragraph"): a DASHBOARD.
   The hero is the animal in its well beside four gauges; the doors are icon
   tiles with one word and a price; below, two columns of compact plates.
   Numbers are big, words are labels, sentences live only in the confirm
   sheet.
   ========================================================================= */

.hub-head { margin-bottom: 18px; }

/* ---- the hero ------------------------------------------------------------- */
.hub-hero { padding: 0; }
.hub-hero.lvc { gap: 22px; align-items: stretch; }
.hub-hero .lvc-specimen { aspect-ratio: 1 / 1; min-height: 300px; }
.hub-hero-main { display: flex; flex-direction: column; gap: 14px; min-width: 0; padding: 22px; }
.hub-hero-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.hub-hero-when { margin-left: auto; color: var(--fg-mute); font-size: var(--tm-h-micro); letter-spacing: .08em; text-transform: uppercase; }
.hub-hero-name { margin: 0; line-height: 1; }
.hub-hero-gate { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; padding: 8px 0; }
.hub-hero-gate .gate-ico { margin: 0; }

.hub-gauges { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin-top: auto; }
.hub-gauge { display: grid; justify-items: center; gap: 6px; padding: 12px 6px 10px; background: var(--surface-2); text-align: center; --g: var(--accent); }
.hub-gauge-ring { position: relative; width: 62px; height: 62px; }
.hub-gauge-ring svg { width: 62px; height: 62px; transform: rotate(-90deg); }
.hub-gauge-ring circle { fill: none; stroke-width: 6; }
.hub-gauge-ring .track { stroke: var(--surface-sink); }
.hub-gauge-ring .fill { stroke: var(--g); stroke-linecap: round; transition: stroke-dasharray .5s ease; }
.hub-gauge-ring svg.ico { position: absolute; inset: 0; width: 62px; height: 62px; transform: none; padding: 19px; color: var(--g); }
.hub-gauge b { font-family: var(--font-display); font-weight: 700; color: var(--fg); }
.hub-gauge span { font-size: var(--tm-h-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute); }
.hub-gauge.is-low { --g: var(--bad); }
.hub-gauge.is-low b { color: var(--bad); }
.hub-gauge.is-unknown b { color: var(--fg-mute); }

.hub-growth { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 10px; }
.hub-growth span { font-size: var(--tm-h-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute); }
.hub-growth i { display: block; height: 6px; border-radius: var(--r-pill); background: var(--surface-sink); overflow: hidden; }
.hub-growth i::after { content: ""; display: block; height: 100%; width: var(--w, 0%); background: var(--accent); border-radius: var(--r-pill); transition: width .5s ease; }
.hub-growth b { font-family: var(--font-display); font-weight: 700; color: var(--fg); }

/* THE WELL WITH NO MODEL. The engine leaves an empty frame when a species has
   no bake on this box (every Legacy species today - the client pak key is not
   recovered). An empty black box reads as broken, so the frame says the
   species' name and what is coming. */
.hub-hero .lvc-specimen-mount[data-empty]::before {
  content: attr(data-species);
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 90%; text-align: center; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(20px, 2.6vw, 30px); letter-spacing: .06em; text-transform: uppercase;
  color: color-mix(in srgb, var(--fg) 26%, transparent);
}
.hub-hero .lvc-specimen-mount[data-empty]::after {
  content: "3D preview coming";
  position: absolute; left: 0; right: 0; bottom: 14px; text-align: center;
  font-size: var(--tm-h-micro); font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-mute);
}
/* the engine's own poster disc is noise under our own placeholder */
.hub-hero .lvc-specimen-mount[data-empty] .shopview[data-view]::after { content: none; }

/* ---- plates --------------------------------------------------------------- */
.hub-plate { padding: 18px 20px 18px; }
.hub-plate-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.hub-plate-head h2 { font-size: var(--tm-h-sec); margin: 0; }
.hub-chips { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.hub-chip b { font-family: var(--font-display); font-weight: 700; }
.hub-chip-accent { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.hub-chip-warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.hub-chip-bad { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 45%, transparent); }
.hub-chip-ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.hub-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; align-items: start; }
.hub-col { min-width: 0; }

/* ---- the doors: icon tiles ------------------------------------------------ */
.hub-tiles { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 8px; }
.hub-tile {
  display: grid; justify-items: center; gap: 6px; padding: 12px 6px 10px;
  background: var(--surface-2); color: var(--fg); cursor: pointer; font: inherit; text-align: center;
  transition: border-color .15s ease, transform .15s ease;
}
.hub-tile:hover:not([disabled]) { border-color: color-mix(in srgb, var(--accent) 55%, transparent); transform: translateY(-1px); }
.hub-tile[disabled] { opacity: .42; cursor: not-allowed; }
.hub-tile-ico { width: 38px; height: 38px; border-radius: var(--r-round); display: grid; place-items: center; background: color-mix(in srgb, var(--accent) 14%, var(--surface)); color: var(--accent); }
.hub-tile-ico svg { width: 19px; height: 19px; }
.hub-tile-bad .hub-tile-ico { background: color-mix(in srgb, var(--bad) 14%, var(--surface)); color: var(--bad); }
.hub-tile b { font-family: var(--font-display); font-weight: 600; line-height: 1.15; }
.hub-tile-price { font-size: var(--tm-h-micro); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); }
.hub-tile-price.is-free { color: var(--fg-mute); font-weight: 600; }

/* ---- an inline answer under a plate --------------------------------------- */
.hub-say { margin: 10px 0 0; padding: 9px 12px; line-height: 1.35; background: var(--surface-2); color: var(--fg); }
.hub-say.is-ok { border-color: color-mix(in srgb, var(--ok) 50%, transparent); }
.hub-say.is-bad { border-color: color-mix(in srgb, var(--bad) 50%, transparent); }
.hub-say.is-busy { color: var(--fg-dim); }

/* ---- the vault slots ------------------------------------------------------ */
.hub-slots { display: grid; gap: 8px; }
.hub-slot { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px 12px; align-items: center; padding: 10px 12px; background: var(--surface-2); }
.hub-ring { position: relative; width: 46px; height: 46px; flex: none; }
.hub-ring svg { width: 46px; height: 46px; transform: rotate(-90deg); }
.hub-ring circle { fill: none; stroke-width: 5; }
.hub-ring .track { stroke: var(--surface-sink); }
.hub-ring .fill { stroke: var(--accent); stroke-linecap: round; }
.hub-ring b { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--font-display); font-weight: 700; color: var(--fg); }
.hub-slot-name { min-width: 0; }
.hub-slot-name b { display: block; font-size: var(--tm-h-item); font-family: var(--font-display); font-weight: 700; color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-slot-name span { display: block; font-size: var(--tm-h-micro); letter-spacing: .06em; text-transform: uppercase; color: var(--fg-mute); margin-top: 3px; }
.hub-slot-perks { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 5px; }
.hub-slot-act { grid-column: 1 / -1; display: flex; gap: 6px; flex-wrap: wrap; }
.hub-slot.is-busy { opacity: .7; }
.hub-slot-state { position: absolute; top: 8px; right: 8px; }
.hub-empty { display: grid; justify-items: center; gap: 6px; padding: 22px 10px; text-align: center; background: var(--surface-2); color: var(--fg-dim); }
.hub-empty svg { width: 26px; height: 26px; color: var(--fg-mute); }
.hub-empty b { font-family: var(--font-display); color: var(--fg); }

/* ---- the shop ------------------------------------------------------------- */
.hub-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.hub-tab { cursor: pointer; }
.hub-tab[aria-selected="true"] { color: var(--fg); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.hub-items { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 6px; }
.hub-item {
  display: grid; gap: 4px; padding: 9px 10px; text-align: left; font: inherit; color: var(--fg);
  background: var(--surface-2); cursor: pointer;
  transition: border-color .15s ease, transform .15s ease;
}
.hub-item:hover { border-color: color-mix(in srgb, var(--accent) 55%, transparent); transform: translateY(-1px); }
.hub-item b { font-family: var(--font-display); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-item span { font-size: var(--tm-h-micro); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); }
.hub-item.is-short { opacity: .5; }
.hub-item.is-short span { color: var(--fg-mute); }

/* ---- the wallet ----------------------------------------------------------- */
.hub-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.hub-stat { display: grid; gap: 4px; padding: 12px 14px; background: var(--surface-2); }
.hub-stat span { font-size: var(--tm-h-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute); }
.hub-stat b { font-family: var(--font-display); font-weight: 700; font-size: clamp(24px, 3vw, 32px); line-height: 1; color: var(--fg); letter-spacing: -.01em; }
.hub-lanes { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
.hub-lane code { font-family: var(--font-display); font-weight: 700; }
.hub-ledger { display: grid; gap: 4px; margin-top: 10px; }
.hub-ledger-row { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 6px 10px; background: var(--surface-2); }
.hub-ledger-row b { font-family: var(--font-display); font-weight: 700; }
.hub-ledger-row b.is-up { color: var(--ok); }
.hub-ledger-row b.is-down { color: var(--bad); }
.hub-ledger-row span { color: var(--fg-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-ledger-row time { color: var(--fg-mute); font-size: var(--tm-h-micro); letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; }

/* ---- skins ---------------------------------------------------------------- */
.hub-designs { display: grid; gap: 6px; }
.hub-design { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 8px 10px; background: var(--surface-2); }
.hub-design b { display: block; font-family: var(--font-display); font-weight: 700; }
.hub-design span { display: block; font-size: var(--tm-h-micro); letter-spacing: .06em; text-transform: uppercase; color: var(--fg-mute); margin-top: 2px; }
.hub-swatches { display: inline-flex; gap: 3px; margin-left: 8px; vertical-align: middle; }
.hub-swatches i { width: 10px; height: 10px; border-radius: var(--r); display: inline-block; }

/* ---- forms inside sheets -------------------------------------------------- */
.hub-form { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.hub-form input, .hub-form select { flex: 1 1 160px; min-width: 0; }
.hub-code { font-family: var(--font-display); font-weight: 700; font-size: clamp(22px, 4vw, 30px); line-height: 1.1; letter-spacing: .12em; color: var(--accent); }

/* ---- the confirm sheet ---------------------------------------------------- */
.hub-sheet { border: 0; padding: 0; background: transparent; max-width: min(92vw, 460px); width: 100%; }
.hub-sheet::backdrop { background: color-mix(in srgb, var(--bg-deep) 70%, transparent); backdrop-filter: blur(4px); }
.hub-sheet-in { padding: 22px; display: grid; gap: 10px; color: var(--fg); }
.hub-sheet-in h3 { margin: 0; font-size: var(--tm-h-item); }
.hub-sheet-body { display: grid; gap: 8px; }
.hub-sheet-row { display: flex; justify-content: space-between; gap: 12px; padding: 8px 10px; background: var(--surface-2); }
.hub-sheet-row b { font-family: var(--font-display); }
.hub-sheet-note { margin: 0; }
.hub-sheet-act { display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px; }
.hub-picks { display: grid; gap: 6px; }
.hub-pick { display: flex; align-items: flex-start; gap: 10px; padding: 8px 10px; background: var(--surface-2); cursor: pointer; }
.hub-pick input { margin-top: 3px; }
.hub-pick b { display: block; font-family: var(--font-display); font-weight: 600; }
.hub-pick span { display: block; color: var(--fg-dim); }
.hub-choice { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.hub-choice .btn[aria-pressed="true"] { border-color: color-mix(in srgb, var(--accent) 70%, transparent); background-color: color-mix(in srgb, var(--accent) 16%, var(--surface-2)); }

/* =========================================================================
   THE EVRIMA CARE DECK + THE MONEY DECK (2026-08-24)
   -------------------------------------------------------------------------
   Same grammar as everything above: a record states its GROUND and nothing
   else. The hairline, the radius and the absence of a shadow all arrive from
   terminal.css section 6b, where every class below is named. A `border:` in
   this file would be this sheet answering "what does a box look like" for the
   sixth time, which is the exact drift the register exists to stop.
   ========================================================================= */

/* ---- the island picker (only ever drawn on a two-island owner) ------------ */
.hub-islands { display: inline-flex; gap: 4px; }
.hub-island { cursor: pointer; }
.hub-island[aria-pressed="true"] { color: var(--fg); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }

/* ---- reverse grow -------------------------------------------------------- */
.hub-ungrow { display: grid; gap: 10px; padding: 12px 14px; background: var(--surface-2); margin-bottom: 10px; }
.hub-ungrow-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.hub-ungrow-head b { font-family: var(--font-display); font-weight: 700; font-size: var(--tm-h-item); }
/* THE PREVIEW IS THE POINT OF THE CONTROL: two readings and an arrow, so the
   player sees the trade before they can press it. The target is accented and
   the current value is not - the eye should land on the number that CHANGES. */
.hub-ungrow-read { display: flex; align-items: center; justify-content: center; gap: 14px; }
.hub-ungrow-cell { display: grid; justify-items: center; gap: 2px; min-width: 74px; }
.hub-ungrow-cell i { font-style: normal; font-size: var(--tm-h-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute); }
.hub-ungrow-cell b { font-family: var(--font-display); font-weight: 700; font-size: clamp(22px, 3.4vw, 30px); line-height: 1; color: var(--fg-dim); }
.hub-ungrow-cell.is-to b { color: var(--accent); }
.hub-ungrow-arrow { color: var(--fg-mute); font-size: var(--tm-h-item); }
.hub-ungrow-slider { width: 100%; margin: 0; accent-color: var(--accent); }
.hub-ungrow-slider[disabled] { opacity: .42; cursor: not-allowed; }
.hub-ungrow-act { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.hub-ungrow-num { width: 78px; min-width: 0; text-align: center; font-family: var(--font-display); font-weight: 700; }
.hub-ungrow-act .btn-primary { margin-left: auto; }

/* A wider door row: the care tiles carry a CURRENCY NAME in their price, and
   at eight-across ("5 NADDERS") the word wraps under the number on a laptop.
   ★ AUTO-FIT, NOT A FIXED COUNT. How many doors this row holds is the
   catalog's answer, not this sheet's - an island with one diet letter draws
   four tiles and one with three draws six, and a fixed five-column grid
   orphans the sixth on a row of its own. */
.hub-tiles-wide { grid-template-columns: repeat(auto-fit, minmax(124px, 1fr)); }

/* ---- the money deck ------------------------------------------------------ */
.hub-money { display: grid; grid-template-columns: minmax(0, 320px) minmax(0, 1fr); gap: 12px; align-items: start; }
.hub-card { display: grid; gap: 10px; padding: 14px 16px; background: var(--surface-2); }
.hub-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.hub-card-head b { font-family: var(--font-display); font-weight: 700; font-size: var(--tm-h-item); }

/* THE WORK PRESS IS THE WHOLE TARGET. A small button inside a large card is a
   target a thumb misses, and this is the one door a player presses every
   hour. The ring is the cooldown's own gauge, drawn from the server's clock. */
.hub-work { justify-items: center; text-align: center; }
/* Its GROUND and its hairline are spoken in terminal.css section 6b, where
   "this surface is deliberately not a plate" belongs - the register is the
   one list of what a surface IS, and an exception buried in a page sheet is
   how the eleven surfaces drifted apart in the first place. */
.hub-work-press { display: grid; place-items: center; padding: 0; cursor: pointer; font: inherit; color: var(--fg); }
.hub-work-press[disabled] { cursor: not-allowed; }
.hub-work-ring { position: relative; display: grid; place-items: center; width: 132px; height: 132px; }
.hub-work-ring svg { position: absolute; inset: 0; width: 132px; height: 132px; transform: rotate(-90deg); }
.hub-work-ring circle { fill: none; stroke-width: 7; }
.hub-work-ring .track { stroke: var(--surface-sink); }
.hub-work-ring .fill { stroke: var(--accent); stroke-linecap: round; transition: stroke-dasharray 1s linear; }
.hub-work-ring.is-cooling .fill { stroke: var(--fg-mute); }
.hub-work-face { display: grid; justify-items: center; gap: 4px; }
.hub-work-ico { display: grid; place-items: center; width: 34px; height: 34px; color: var(--accent); }
.hub-work-ico svg { width: 26px; height: 26px; }
.hub-work-ring.is-cooling .hub-work-ico { color: var(--fg-mute); }
.hub-work-face b { font-family: var(--font-display); font-weight: 700; font-size: var(--tm-h-micro); letter-spacing: .1em; text-transform: uppercase; }
.hub-work-press:hover:not([disabled]) .hub-work-ring .fill { stroke: var(--ok); }
/* THE REVEAL. It animates ONCE, on the frame the receipt lands - a payout a
   player never sees arrive is a payout they think did not happen. Held to a
   transform and an opacity so a reduced-motion reader loses the movement and
   keeps the number. */
.hub-work-got { min-height: 1.4em; margin: 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(20px, 3vw, 28px); line-height: 1.2; color: var(--ok); opacity: 0; }
.hub-work-got.is-in { animation: hub-got .6s ease-out forwards; }
@keyframes hub-got {
  from { opacity: 0; transform: translateY(8px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hub-work-got.is-in { animation: none; opacity: 1; }
  .hub-work-ring .fill { transition: none; }
}
.hub-work-rate { margin: 0; font-size: var(--tm-h-micro); letter-spacing: .08em; text-transform: uppercase; }

/* ---- transfer ------------------------------------------------------------ */
.hub-xfer-form { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto; gap: 8px; align-items: end; position: relative; }
.hub-xfer-field { display: grid; gap: 4px; min-width: 0; }
.hub-xfer-field i { font-style: normal; font-size: var(--tm-h-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute); }
.hub-xfer-field input { width: 100%; min-width: 0; }
/* THE DROP-DOWN IS THE REGISTER'S FLOATING KIND: it sits over page content,
   so it keeps an opaque ground and the panel lift - both spoken in the house
   look beside the Bans tab's list, which is the same shape. */
.hub-xfer-list { position: absolute; z-index: 2; top: 100%; left: 0; width: min(100%, 320px); margin-top: 4px; padding: 4px; list-style: none; max-height: 216px; overflow-y: auto; background: var(--surface); }
.hub-xfer-list li { display: block; }
.hub-xfer-list button { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 8px; padding: 7px 10px; background: none; border: 0; cursor: pointer; font: inherit; color: var(--fg); text-align: left; }
.hub-xfer-list button:hover, .hub-xfer-list button:focus-visible { background: var(--surface-2); }
.hub-xfer-list b { font-family: var(--font-display); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 900px) {
  .hub-tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .hub-cols { grid-template-columns: minmax(0, 1fr); }
  .hub-money { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .hub-hero .lvc-specimen { min-height: 0; aspect-ratio: 4 / 3; }
  .hub-hero-main { padding: 14px; }
  .hub-gauges { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hub-plate { padding: 14px 12px 12px; }
  .hub-ledger-row { grid-template-columns: 60px minmax(0, 1fr); }
  .hub-ledger-row time { display: none; }
  .hub-tiles-wide { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hub-ungrow-act .btn-primary { margin-left: 0; width: 100%; }
  /* The send button drops to its own full-width row rather than being
     squeezed to an ellipsis beside two fields. */
  .hub-xfer-form { grid-template-columns: minmax(0, 1fr); }
  .hub-xfer-form .btn { width: 100%; }
  .hub-ungrow-cell { min-width: 60px; }
}
