/* ═══════════════════════════════════════════════════════════════════════════
   FROSTVEIN, TERMINAL

   A fracture instrument reading one plate of ice. The rules, without exception:

     · Radius is 0. Everywhere. There is no --r token because there is nothing
       to tune: a corner is a corner.
     · Elevation does not exist. No shadow, no glow, no gradient on any chrome
       surface. Separation is a 1px rule, and where a group is interactive it
       is a 1px box. Everything sits directly on --bg.
     · Monospace carries every number, label, row and readout. Big Shoulders
       Display, condensed and cut, carries headings and nothing else. Two
       families, one of them free.
     · Motion is 80ms linear or it is a hard cut. Nothing eases, nothing
       loops, nothing slides.
     · One signal colour, --accent, and it is the light inside the ice. It is
       spent on the live reading, the active channel and the pressed control.
       Everywhere else the panel is cold grey on frozen black.

   The house shape is the rhomb: the gems are rhombs, the head of the crack is
   a rhomb, so every node, bullet and section marker is a 1px rhomb too.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Written from JS by applySafeArea(). 0 outside Telegram fullscreen, so
     every utility that reads them collapses on its own. */
  --tg-safe-top: 0px;
  --tg-safe-bottom: 0px;

  /* Duplicated from brand.js so the splash paints correctly on frame one,
     before shell.js has stamped the palette onto <html>. */
  --bg:       #030E13;
  --surface:  #071A22;
  --tint:     #0B2029;
  --tint-2:   #123340;
  --line:     #1C4453;
  --ink:      #E8FAFF;
  --ink-2:    #9BBDC9;
  --ink-3:    #6F919E;
  --accent:   #67E8F9;
  --accent-d: #A5F3FC;
  --good:     #5EEAD4;
  --warn:     #FB7185;

  /* System monospace: no request, no layout shift, tabular by default on every
     platform this ships to. The panel is legible before a single font byte has
     arrived, which on a cheap Android is the whole first second. */
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, "Roboto Mono",
          "DejaVu Sans Mono", "Courier New", monospace;
  --disp: "Big Shoulders Display", "Arial Narrow", Impact, sans-serif;

  --hair: 1px solid var(--line);
  --t: 80ms linear;      /* the entire motion budget */
  --u: 8px;              /* the rhythm; every gap is a multiple of it */
}

*, *::before, *::after {
  box-sizing: border-box;
  border-radius: 0;                       /* the rule, enforced */
  -webkit-tap-highlight-color: transparent;
}

/* Overlays set their own display, which outranks the UA rule for [hidden]. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg);
  overscroll-behavior: none;
  -webkit-overflow-scrolling: touch;
}

body {
  font-family: var(--mono);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  /* A double tap on a label must not select the label. Chrome, not a document. */
  -webkit-user-select: none; user-select: none;
}
/* The one place text is meant to be read rather than tapped. */
.drawer-b { -webkit-user-select: text; user-select: text; }

button, input { font: inherit; color: inherit; }
button { border: 0; background: none; padding: 0; cursor: pointer; }

/* The glyph sheet itself never renders. */
.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ── glyphs ──────────────────────────────────────────────────────────────── */

.g {
  display: block; flex: none;
  width: 20px; height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: butt;                   /* fracture, not calligraphy */
  stroke-linejoin: miter;
}
.g-sm { width: 16px; height: 16px; }
.g-lg { width: 30px; height: 30px; }

/* The rhomb: node, bullet, section marker. One shape, three jobs. */
.sec-t::before,
.vx-row::after,
.drawer-b li::before {
  content: "";
  width: 5px; height: 5px;
  border: 1px solid var(--accent);
  transform: rotate(45deg);
}

/* ── type roles ──────────────────────────────────────────────────────────── */

/* Section label: a marker, a condensed heading, a right hand reading, and the
   rule that separates it from whatever it introduces. */
.sec {
  display: flex; align-items: baseline; gap: var(--u);
  margin: calc(var(--u) * 2.5) 0 0;
  padding-bottom: 6px;
  border-bottom: var(--hair);
}
.sec-t {
  font-family: var(--disp);
  font-size: 17px; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--ink);
}
.sec-t::before { display: inline-block; margin-right: 9px; vertical-align: 3px; }
.sec-v {
  margin-left: auto;
  font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}
.sec-v.is-done { color: var(--good); }

/* The one block of running prose on Home. Mono like everything else, because
   an instrument does not change voice halfway down the panel. */
.lead {
  margin: calc(var(--u) * 1.5) 0 0;
  font-size: 12.5px; line-height: 1.6;
  color: var(--ink-2);
}
.lead b { color: var(--ink); font-weight: 700; }

.foot {
  margin: calc(var(--u) * 2) 0 0;
  font-size: 10.5px; line-height: 1.6;
  color: var(--ink-3);
}

/* ── frame ───────────────────────────────────────────────────────────────── */

#app { position: fixed; inset: 0; display: flex; flex-direction: column; background: var(--bg); }

/* There is no brand bar, so <main> carries the fullscreen top inset for every
   screen. The panels are absolutely positioned inside it and therefore sit
   against its PADDING box, which is exactly the reserved band. */
main {
  flex: 1; min-height: 0; position: relative;
  padding-top: max(var(--tg-safe-top), env(safe-area-inset-top, 0px));
}
/* Fullscreen already reserves the chrome inset; trim a cosmetic sliver so the
   first rule does not read as a gap, floored at the inset itself. */
[data-fullscreen="1"] main {
  padding-top: max(var(--tg-safe-top),
    calc(max(var(--tg-safe-top), env(safe-area-inset-top, 0px)) - 1.4vh));
}

.scr {
  position: absolute; inset: 0;
  display: none; flex-direction: column;
  overflow-y: auto;
  padding: 0 12px 24px;
}
.scr.is-active { display: flex; }
/* A scrolling flex column shrinks its children by default, and anything whose
   height comes from CSS rather than from text collapses: the daily gauge is a
   10px box holding a 0-height fill, so it flattened to its own padding. Pin
   every child at its natural size. Play is excluded because its plate is the
   one element in the app that IS meant to take the leftover space. */
.scr:not(.scr--play) > * { flex: none; }
.scr:not(.scr--play) > :first-child { margin-top: 12px; }
.scr--play { overflow: hidden; padding: 0 10px 8px; }

/* Play is the game and nothing else: the tab bar steps aside so the plate
   owns the screen. */
[data-screen="play"] .tabs { display: none; }

/* ── bottom tab bar: four channels, standard mobile position ──────────────────
   A flex-column child of #app, so it pins to the bottom of the fixed viewport
   above the scrolling content. Glyph and label on ONE line. No fill, no
   elevation: one rule above it, one rule between each channel. The live
   channel is flagged by a solid node, never by a filled cell. */
.tabs {
  flex: none;
  display: grid; grid-template-columns: repeat(4, 1fr);
  border-top: var(--hair);
  background: var(--bg);
  padding-bottom: max(var(--tg-safe-bottom), env(safe-area-inset-bottom, 0px));
}
.tab {
  position: relative;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 13px 2px;
  color: var(--ink-3);
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  transition: color var(--t), background var(--t);
}
.tab + .tab { border-left: var(--hair); }
.tab:active { background: var(--tint); }
.tab.is-on { color: var(--accent); }
.tab.is-on::before {
  content: ""; position: absolute; left: 8px; top: 50%;
  width: 4px; height: 4px; margin-top: -2px;
  background: var(--accent);
  transform: rotate(45deg);
}

/* ── HOME: identity line ─────────────────────────────────────────────────── */

.ident {
  display: flex; align-items: center; gap: var(--u);
  padding-bottom: var(--u);
  border-bottom: var(--hair);
}
.ident-m { color: var(--accent); display: block; }
.ident-n {
  font-family: var(--disp);
  font-size: 19px; font-weight: 800;
  letter-spacing: 0.16em; text-transform: uppercase;
}
/* shell.js writes every [data-rank-badge], so the tag and the index readout
   below it can never disagree. */
.ident-r {
  margin-left: auto;
  padding: 3px 7px;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
}

/* ── HOME: VEIN INDEX ────────────────────────────────────────────────────────
   The module this game earns. A crack path is a TREE, so the grade scale is
   printed as one: a trunk, a rhomb node at every threshold, an elbow out to
   the name. Static by design, because a printed scale on an instrument does
   not move; the only live thing is the reading clamped above it. */
.vx-read {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; column-gap: 12px;
  padding: 12px 0;
  border-bottom: var(--hair);
}
.vx-num {
  font-size: 44px; font-weight: 700; line-height: 0.9;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.vx-unit {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-2);
}
.vx-unit i { font-style: normal; color: var(--ink-3); letter-spacing: 0.14em; }
.vx-grade {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--accent);
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
}

.vx-cols {
  display: grid; grid-template-columns: 1fr auto;
  padding: 7px 0 7px 24px;
  border-bottom: var(--hair);
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
}

.vx-tree {
  position: relative;
  margin: 0; padding: 0 0 0 24px;
  list-style: none;
  border-bottom: var(--hair);
}
/* the trunk: first node to last node, nothing before, nothing after */
.vx-tree::before {
  content: ""; position: absolute;
  left: 8px; top: 16px; bottom: 16px;
  border-left: var(--hair);
}
.vx-row {
  position: relative;
  display: grid; grid-template-columns: 1fr auto;
  align-items: center; column-gap: var(--u);
  height: 32px;
}
/* the elbow out of the trunk */
.vx-row::before {
  content: ""; position: absolute;
  left: -16px; top: 16px; width: 14px;
  border-top: var(--hair);
}
/* the node itself, sat on the trunk */
.vx-row::after {
  position: absolute;
  left: -16px; top: 16px;
  margin: -3px 0 0 -3px;
  border-color: var(--line);
}
.vx-nm {
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-2);
}
.vx-th {
  font-size: 13px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* ── HOME: today's target ────────────────────────────────────────────────── */

.task { display: flex; align-items: baseline; gap: var(--u); margin-top: 10px; }
.task-l { flex: 1; min-width: 0; font-size: 11.5px; color: var(--ink-2); }
.task-v { flex: none; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* The gauge: a hairline track and a solid fill. Where it reads a live physical
   quantity it wears a tick rule under it, which is what makes it a caliper
   rather than a progress bar. */
.gg {
  position: relative;
  height: 10px; margin-top: 6px; padding: 2px;
  border: var(--hair);
}
.gg i {
  display: block; height: 100%; width: 0;
  background: var(--accent);
  transition: width var(--t), background var(--t);
}
.gg i.is-low { background: var(--warn); }
.gg--tick { margin-top: 0; }
.gg--tick::after {
  content: ""; position: absolute;
  left: 0; right: 0; top: 100%; height: 4px;
  background: repeating-linear-gradient(90deg, var(--line) 0 1px, transparent 1px 10%);
}

/* ── HOME: the log, as a cell matrix ─────────────────────────────────────── */

.mtx { display: grid; grid-template-columns: 1fr 1fr; border: var(--hair); border-top: 0; }
.mtx-c {
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 10px 11px;
}
.mtx-c:nth-child(even) { border-left: var(--hair); }
.mtx-c:nth-child(n+3) { border-top: var(--hair); }
.mtx-c b { font-size: 20px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.mtx-c span {
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-3);
}

/* ── bars: the only button shape in the app ──────────────────────────────────
   Full width, 1px border, NO fill until pressed, label left, glyph trailing in
   its own ruled cell. Two rows when there is a sub-line, one when there is
   not. */
.act {
  position: relative;
  display: grid; grid-template-columns: 1fr auto;
  align-items: center; column-gap: 12px;
  width: 100%; margin-top: 10px;
  padding: 11px 12px;
  border: var(--hair);
  color: var(--ink);
  text-align: left;
  transition: background var(--t), border-color var(--t), color var(--t);
}
/* the rule that boxes the trailing glyph off from the label */
.act::after {
  content: ""; position: absolute;
  top: 0; bottom: 0; right: 44px;
  border-left: var(--hair);
}
.act-t {
  grid-column: 1;
  font-family: var(--disp);
  font-size: 18px; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase;
}
.act-s {
  grid-column: 1; grid-row: 2;
  margin-top: 4px;
  font-size: 10.5px; line-height: 1.5;
  color: var(--ink-2);
}
.act-s i { display: block; font-style: normal; }
.act-s i:empty { display: none; }
.act-g { grid-column: 2; grid-row: 1 / -1; align-self: center; color: var(--ink-3); }

.act:active { background: var(--tint-2); }
.act:disabled { opacity: 0.45; }

.act--live { border-color: var(--accent); color: var(--accent); }
.act--live::after { border-left-color: var(--accent); }
.act--live .act-s { color: var(--accent-d); }
.act--live .act-g { color: var(--accent); }
.act--live:active { background: var(--accent); color: var(--bg); }
.act--live:active .act-s,
.act--live:active .act-g { color: var(--bg); }

/* The square control: pause, back, close. Same border, same no-fill rule. */
.ctl {
  width: 36px; height: 36px; flex: none;
  display: grid; place-items: center;
  border: var(--hair);
  color: var(--ink);
  transition: background var(--t);
}
.ctl:active { background: var(--tint-2); }

/* ── PLAY ────────────────────────────────────────────────────────────────── */

/* Count first, unit beside it. Both controls sit right, away from the thumb
   that is tapping the plate. */
.rig {
  flex: none;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 0;
  border-bottom: var(--hair);
}
.rig-sc { display: flex; align-items: baseline; gap: 8px; }
.rig-v {
  font-size: 30px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.rig-k {
  font-style: normal;
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
}
/* The chain carries margin-left:auto whether or not it is lit, so the shield
   tag and both controls stay pinned right in every state. */
.rig-x {
  margin-left: auto;
  font-size: 15px; font-weight: 700;
  color: var(--accent);
  opacity: 0;
  transition: opacity var(--t);
}
.rig-x.is-on { opacity: 1; }
.rig-sh {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 7px;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
}

/* Live clearance between the head of the crack and the rock, on one line:
   label left, caliper right. It drains as you lean into a wall. */
.clr {
  flex: none;
  display: grid; grid-template-columns: auto 1fr;
  align-items: center; column-gap: 10px;
  padding: 10px 0 14px;
}
.clr-k {
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
}

/* The plate: a hairline box and nothing else. All the light in this app comes
   out of the canvas, never off the chrome around it. */
.plate {
  flex: 1; min-height: 0; position: relative;
  border: var(--hair);
  background: var(--bg);
  overflow: hidden;
  margin-bottom: 4px;
}
#stage { display: block; width: 100%; height: 100%; touch-action: none; }

/* Cause and effect, four rows. Top aligned, not centred: a printout starts at
   the top of the page. Scrolls on short phones instead of squeezing. */
.cold {
  position: absolute; inset: 0; z-index: 3;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 12px;
  background: var(--bg);
  overflow-y: auto;
}
.cold-in { width: 100%; max-width: 340px; }
.cold-in .sec { margin-top: 0; }

.io { margin: 0; }
.io-r {
  display: grid; grid-template-columns: 104px 1fr;
  column-gap: 12px; align-items: start;
  padding: 10px 0;
  border-bottom: var(--hair);
}
.io-k {
  display: flex; align-items: center; gap: 7px;
  margin: 0;
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink);
}
.io-k .g { color: var(--ink-3); }
.io-v { margin: 0; font-size: 11px; line-height: 1.5; color: var(--ink-2); }

/* ── RANK ────────────────────────────────────────────────────────────────── */

/* An interactive group is boxed; the selected channel is inverted, because a
   toggle has to be readable in a glance and there is no fill anywhere else to
   confuse it with. */
.toggle { display: grid; grid-template-columns: 1fr 1fr; border: var(--hair); margin-top: 10px; }
.seg-btn {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 11px 6px;
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-3);
  transition: color var(--t), background var(--t);
}
.seg-btn + .seg-btn { border-left: var(--hair); }
.seg-btn:active { background: var(--tint); }
.seg-btn.is-on { background: var(--accent); color: var(--bg); }

.led-h {
  display: grid; grid-template-columns: 26px 1fr auto;
  column-gap: 10px;
  margin-top: 14px; padding: 0 2px 7px;
  border-bottom: var(--hair);
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-3);
}
.led-h span:last-child { text-align: right; }

.ledger { display: flex; flex-direction: column; }
/* shell.js writes .rw / .rw-pos / .rw-av / .rw-nm / .rw-sc, so those names are
   fixed. Everything about how they look is not. */
.rw {
  display: grid; grid-template-columns: 26px 20px 1fr auto;
  align-items: center; column-gap: 10px;
  min-height: 38px; padding: 0 2px;
  border-bottom: var(--hair);
}
.rw-pos { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--ink-3); }
/* shell.js hands each name a hue. It gets one underline in that hue and
   nothing else, so the cyan stays the only saturated thing on the panel. */
.rw-av {
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-bottom: 1px solid hsl(var(--h) 12% 38%);
  color: hsl(var(--h) 16% 66%);
  font-size: 10.5px; font-weight: 700;
}
.rw-nm {
  font-size: 12.5px; letter-spacing: 0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rw-sc {
  min-width: 56px; padding-left: 10px;
  border-left: var(--hair);
  text-align: right;
  font-size: 14px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.rw--top .rw-pos { color: var(--accent); }
.rw--me { border-bottom-color: var(--accent); }
.rw--me .rw-pos, .rw--me .rw-nm, .rw--me .rw-sc { color: var(--accent); }

/* ── MORE ────────────────────────────────────────────────────────────────── */

.opts { border: var(--hair); margin-top: 10px; }
.opt {
  display: flex; width: 100%; align-items: center; gap: 12px;
  min-height: 46px; padding: 0 10px;
  font-size: 12.5px; letter-spacing: 0.02em;
  color: var(--ink); text-align: left;
}
.opt + .opt { border-top: var(--hair); }
.opt > span { flex: 1; min-width: 0; }
.opt > .g { color: var(--ink-3); }
.opt-g { color: var(--ink-3); }
.opt--go { transition: background var(--t); }
.opt--go:active { background: var(--tint); }

/* The switch is square too: a block that snaps between two stops, which is
   what a switch actually is once you stop drawing it as a pill. */
.sw {
  appearance: none; -webkit-appearance: none;
  width: 38px; height: 20px; flex: none; margin: 0;
  position: relative;
  background: none;
  border: var(--hair);
  transition: border-color var(--t);
}
.sw::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 14px; height: 14px;
  background: var(--ink-3);
  transition: transform var(--t), background var(--t);
}
.sw:checked { border-color: var(--accent); }
.sw:checked::after { transform: translateX(18px); background: var(--accent); }

/* ── overlays ────────────────────────────────────────────────────────────── */

.veil { position: fixed; inset: 0; z-index: 40; background: rgba(0, 3, 5, .8); }

/* Full bleed to the bottom edge, squared off. A sheet with corners is not a
   card that slid up, it is a panel that opened. Deliberately not animated: a
   sheet that slides has its own Close control under the fold while it moves. */
.drawer {
  position: fixed; z-index: 50;
  left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column;
  background: var(--bg);
  border-top: var(--hair);
  max-height: calc(100dvh - max(var(--tg-safe-top), env(safe-area-inset-top, 0px)) - 32px);
  padding-bottom: max(var(--tg-safe-bottom), env(safe-area-inset-bottom, 0px));
}
.drawer-h {
  flex: none;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border-bottom: var(--hair);
  color: var(--accent);
}
.drawer-h b {
  flex: 1; min-width: 0;
  font-family: var(--disp);
  font-size: 18px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink);
}
.drawer-b {
  flex: 1; min-height: 0;
  overflow-y: auto;
  padding: 12px 14px 4px;
  font-size: 12.5px; line-height: 1.65;
  color: var(--ink-2);
}
.drawer-b p { margin: 0 0 10px; }
.drawer-b ul { margin: 0 0 10px; padding: 0; list-style: none; }
.drawer-b li { position: relative; padding-left: 18px; margin-bottom: 10px; }
.drawer-b li::before { position: absolute; left: 0; top: 7px; }
.drawer-b b { color: var(--ink); font-weight: 700; }
.drawer-f { flex: none; padding: 0 12px 12px; border-top: var(--hair); }

/* Dialogs are full width BANDS ruled top and bottom, not floating cards. A
   card implies elevation, and there is none anywhere in this app. */
.band {
  position: fixed; inset: 0; z-index: 55;
  display: flex; align-items: center;
  pointer-events: none;
}
.band-in {
  pointer-events: auto;
  width: 100%;
  padding: 0 12px 14px;
  background: var(--bg);
  border-top: var(--hair);
  border-bottom: var(--hair);
  animation: cut 80ms linear;
}
@keyframes cut { from { opacity: 0; } to { opacity: 1; } }
.band-in .sec { margin-top: 12px; }

.rep {
  display: grid; grid-template-columns: auto auto 1fr;
  align-items: baseline; column-gap: 10px;
  padding: 12px 0;
  border-bottom: var(--hair);
}
.rep-n {
  font-size: 48px; font-weight: 700; line-height: 0.9;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.rep-u {
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-2);
}
.rep-s {
  justify-self: end;
  font-size: 10.5px; letter-spacing: 0.04em;
  color: var(--ink-3);
}

.band-t {
  display: flex; align-items: center; gap: 8px;
  margin: 12px 0 0;
  font-size: 13px; font-weight: 700;
  color: var(--ink);
}
.band-t .g { color: var(--warn); }
.band-p { margin: 10px 0 0; font-size: 11.5px; line-height: 1.55; color: var(--ink-2); }
.band-btns { display: grid; grid-template-columns: 1fr 1fr; gap: var(--u); }
.band-btns .act { padding: 11px 10px; }
.band-btns .act::after { right: 40px; }
.band-btns .act-t { font-size: 15px; }

/* The revive countdown: one stamped numeral in a band, cut in, never scaled. */
.cdn { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; pointer-events: none; }
.cdn span {
  display: block; width: 100%;
  padding: 16px 0;
  background: var(--bg);
  border-top: 1px solid var(--accent);
  border-bottom: 1px solid var(--accent);
  color: var(--accent);
  font-size: 64px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
  text-align: center;
  animation: cut 80ms linear;
}

.msg {
  position: fixed; z-index: 70;
  left: 12px; right: 12px;
  bottom: calc(84px + max(var(--tg-safe-bottom), env(safe-area-inset-bottom, 0px)));
  background: var(--bg);
  border: var(--hair);
  padding: 11px 12px;
  font-size: 11.5px; letter-spacing: 0.02em;
}

/* ── splash ──────────────────────────────────────────────────────────────── */

#splash {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center;
  padding: 0 24px;
  background: var(--bg);
  transition: opacity 80ms linear;
}
#splash.out { opacity: 0; }
.boot { width: 100%; border-top: var(--hair); border-bottom: var(--hair); padding: 18px 0; }
.boot-m { color: var(--accent); display: block; }
.boot-n {
  margin-top: 12px;
  font-family: var(--disp);
  font-size: 34px; font-weight: 800; line-height: 1;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.boot-s {
  margin-top: 8px;
  font-size: 9.5px; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--ink-3);
}

/* ── reduce motion: kill all of it ───────────────────────────────────────── */

[data-reduce-motion="1"] *,
[data-reduce-motion="1"] *::before,
[data-reduce-motion="1"] *::after {
  animation: none !important;
  transition: none !important;
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* Short phones: the index gives up row height first, then the big numerals. */
@media (max-height: 690px) {
  .vx-row { height: 27px; }
  .vx-row::before, .vx-row::after { top: 13.5px; }
  .vx-tree::before { top: 13.5px; bottom: 13.5px; }
  .vx-num { font-size: 36px; }
  .rep-n { font-size: 40px; }
  .rig-v { font-size: 25px; }
  .lead { font-size: 11.5px; }
  .sec { margin-top: 16px; }
  .io-r { padding: 8px 0; }
  .io-v { font-size: 10.5px; }
}
