/* The Board's card table. Two places facing each other: Meridian's datacenter
   across the top, Catalyst's secondhand cyberdeck along the bottom. Card art
   and symbols carry the color; scenery stays dim and still, and anything that
   lights up or moves means something in the game. Motion explains change and
   switches off with reduced motion. Mats and skins are classes on .board, so
   other corporations and earned Runner skins can restyle them. */

/* --- typefaces: Atkinson Hyperlegible Next and Mono, bundled (SIL OFL 1.1;
   see THIRD_PARTY.md). Extended Latin loads only when a name needs it. ------- */
@font-face { font-family: "Atkinson Hyperlegible Next"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url(/fonts/atkinson-hyperlegible-next-latin-wght-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Atkinson Hyperlegible Next"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url(/fonts/atkinson-hyperlegible-next-latin-ext-wght-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Atkinson Hyperlegible Next"; font-style: italic; font-weight: 200 800; font-display: swap;
  src: url(/fonts/atkinson-hyperlegible-next-latin-wght-italic.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Atkinson Hyperlegible Next"; font-style: italic; font-weight: 200 800; font-display: swap;
  src: url(/fonts/atkinson-hyperlegible-next-latin-ext-wght-italic.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Atkinson Hyperlegible Mono"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url(/fonts/atkinson-hyperlegible-mono-latin-wght-normal.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Atkinson Hyperlegible Mono"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url(/fonts/atkinson-hyperlegible-mono-latin-ext-wght-normal.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

:root {
  --bg: #070b10;
  --panel: #0e151d;
  --panel-2: #121b25;
  --line: #22303f;
  --fg: #e3e9f0;
  --dim: #93a0b2;
  --faint: #7b889c;
  --corp: #b48cff;
  --runner: #5fe3e8;
  --latch: #5fe3e8;
  --latch-mark: #f4f7fb;     /* Latch AI's pointer and markers: white, never a game color */
  --gold: #f2c35a;
  --alert: #e07a6e;
  --hear: #b59dff;
  --mat-ink: #7fd6a3;        /* Meridian's regulatory green */
  --mat-light: #d9a441;      /* service lights */
  --ui: "Atkinson Hyperlegible Next", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: "Atkinson Hyperlegible Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* One card size for everything on the table, in real card proportions
     (63 x 88 mm). Only cards lifted off the table for reading are bigger. */
  --card-w: calc(clamp(62px, min(6.2vw, 9.4vh), 118px) * var(--fit, 1));
  --card-h: calc(var(--card-w) * 1.4);
  --r-card: calc(var(--card-w) * .075);
  --r-panel: 12px;
  --r-chip: 6px;

  /* Elevation: resting on the table, lifted in the hand, panels over the table. */
  --e1: 0 1px 2px rgba(0,0,0,.5), 0 6px 14px rgba(0,0,0,.38);
  --e2: 0 4px 8px rgba(0,0,0,.45), 0 18px 36px rgba(0,0,0,.45);
  --e3: 0 2px 8px rgba(0,0,0,.4), 0 22px 56px rgba(0,0,0,.62);

  /* Motion: the Runner's things have a little spring; Meridian's machinery
     moves steadily. */
  --t-fast: 120ms;
  --t-med: 220ms;
  --t-slow: 420ms;
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-spring: cubic-bezier(.34, 1.5, .64, 1);
  --ease-mech: cubic-bezier(.65, 0, .35, 1);
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--fg); font: 15px/1.45 var(--ui); }
button { font: inherit; color: inherit; cursor: pointer; }
button:disabled { cursor: default; }
:focus-visible { outline: 2px solid var(--latch); outline-offset: 2px; }
#root { height: 100%; }

/* --- NSG game symbols, recolored with a mask over the unmodified files ---- */
.sym { display: inline-block; width: 1.05em; height: 1.05em; vertical-align: -0.16em; background-color: currentColor;
  -webkit-mask: var(--m) center / contain no-repeat; mask: var(--m) center / contain no-repeat; flex: none; }
.sym-click { --m: url(/symbols/click.svg); }
.sym-credit { --m: url(/symbols/credit.svg); }
.sym-agenda { --m: url(/symbols/agenda.svg); }
.sym-mu { --m: url(/symbols/mu.svg); }
.sym-tag { --m: url(/symbols/tag.svg); }
.sym-sub { --m: url(/symbols/sub.svg); }
.sym-advance { --m: url(/symbols/advance.svg); }
.sym-hq { --m: url(/symbols/hq.svg); }
.sym-rd { --m: url(/symbols/rd.svg); }
.sym-archives { --m: url(/symbols/archives.svg); }

/* --- sitting down ------------------------------------------------------- */
.splash { height: 100%; display: grid; place-items: center; padding: 24px 16px;
  background: radial-gradient(900px 500px at 50% 0%, #17233a, transparent 70%), var(--bg); }
.sitdown { max-width: 460px; display: grid; gap: 14px; justify-items: start; }
.sitdown h1 { margin: 6px 0 0; font-size: 30px; }
.sitdown .fine { color: var(--faint); font-size: 13px; }
.latchsays { margin: 0; }
.primary { background: color-mix(in oklab, var(--latch) 26%, #0c1820); border: 1px solid color-mix(in oklab, var(--latch) 55%, #0c1820);
  border-radius: 10px; padding: 10px 18px; font-weight: 700; transition: background var(--t-fast); }
.primary:hover:not(:disabled) { background: color-mix(in oklab, var(--latch) 36%, #0c1820); }
.primary:active:not(:disabled) { transform: translateY(1px); }
.primary.small, .ghost.small { padding: 5px 12px; font-size: 13px; }
.ghost { background: transparent; border: 1px solid transparent; border-radius: 8px; padding: 4px 10px; color: var(--dim); font-size: 13px; }
.ghost:hover { color: var(--fg); border-color: var(--line); }
.ghost.danger { color: var(--alert); }
.confirm { color: var(--dim); font-size: 13px; }
.error { color: var(--alert); font-size: 13px; }
.avatar { image-rendering: pixelated; flex: none; }

/* --- layout ----------------------------------------------------------------- */
.app { height: 100%; display: grid; grid-template-rows: auto 1fr; }
.topbar { display: flex; align-items: center; gap: 12px; padding: 6px max(14px, env(safe-area-inset-left)); background: #080d13; border-bottom: 1px solid #151d28; }
.brand { font-weight: 700; letter-spacing: .14em; text-transform: uppercase; font-size: 12.5px; color: #93b4ff; }
.where { color: var(--faint); font-size: 13px; }
.spacer { flex: 1; }
.layout { position: relative; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; }
.tablewrap { position: relative; min-height: 0; display: grid; grid-template-rows: minmax(0, 1fr); overflow: hidden; }
/* Server details and the match log: a drawer that stays out of the way until
   you select a server or open the log. */
.side { position: absolute; top: 0; right: 0; bottom: 0; width: clamp(280px, 25vw, 360px); z-index: 12; min-height: 0; display: grid; grid-template-rows: auto minmax(0, 1fr);
  border-left: 1px solid #1d2836; background: color-mix(in oklab, var(--panel) 96%, transparent); box-shadow: var(--e3); overflow: hidden;
  transform: translateX(105%); transition: transform var(--t-med) var(--ease-out); }
.side.open, .side.reading { transform: none; }
.side:not(.open) .log { display: none; }
.side:not(.open) .details.empty { display: none; }

/* --- the board ------------------------------------------------------------- */
.board { min-height: 0; display: grid; grid-template-rows: minmax(min-content, 1fr) auto; overflow: auto; }

/* Meridian's side: its datacenter as Catalyst's deck renders it, a virtual
   place rising out of black. Racks are drawn in thin lit edges; the only
   color is Meridian's own regulatory green and amber service lights. The
   floor art shows faintly, strongest nearest the deck. Not a repeating texture. */
.corp-mat { position: relative; display: grid; grid-template-rows: auto minmax(min-content, 1fr) auto; min-height: 0; overflow: hidden;
  background: linear-gradient(180deg, #000 0%, rgba(0,0,0,.94) 35%, rgba(0,0,0,.74) 100%), url(/art/meridian-datacenter.svg) center bottom / cover no-repeat, #000; }
.mat-plain .corp-mat { background: #120e1b; }
.corp-mat.tour { box-shadow: inset 0 0 0 2px var(--latch), inset 0 0 40px color-mix(in oklab, var(--latch) 25%, transparent); }

.strip { display: flex; align-items: center; gap: 16px; padding: 7px 14px; flex-wrap: wrap; font-size: 14px; position: relative; z-index: 2; }
.strip.corp { background: rgba(0,0,0,.55); border-bottom: 1px solid #0f1b1a; }
.strip.tour { box-shadow: inset 0 0 0 2px var(--latch); }
.strip .ident { width: 30px; height: 30px; border-radius: 50%; background: center/cover #222; box-shadow: 0 0 0 2px rgba(255,255,255,.12); }
.name-block { display: grid; line-height: 1.1; }
.name-block .nick { font-size: 15px; letter-spacing: .02em; }
.name-block .group { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; }
.strip.corp .nick { color: #e9f3ee; }
.strip.corp .group { color: var(--mat-ink); }
.strip.runner .nick { color: var(--runner); }
.credits { position: relative; color: var(--gold); font-weight: 700; display: inline-flex; align-items: center; gap: 5px; font-size: 16px; }
.credits .sym { width: 1.25em; height: 1.25em; }
.num { display: inline-block; min-width: 1ch; font-variant-numeric: tabular-nums; }
.floater { position: absolute; left: 100%; top: -2px; font-size: 13px; font-weight: 700; pointer-events: none; animation: floatup 1.4s var(--ease-out) forwards; }
.floater.up { color: #9ff0c4; } .floater.down { color: var(--alert); }
@keyframes floatup { from { transform: translate(4px, 0); opacity: 1; } to { transform: translate(4px, -22px); opacity: 0; } }
.clicks { display: inline-flex; gap: 3px; font-size: 18px; }
.clicks.corp { color: var(--mat-ink); }
.clicks.runner { color: var(--runner); }
.clicks .sym.spent { opacity: .2; }
.clicks .sym.on { filter: drop-shadow(0 0 4px currentColor); }
.points { display: inline-flex; align-items: center; gap: 5px; background: transparent; border: 1px solid transparent; border-radius: var(--r-chip); padding: 1px 6px; margin: 0 -6px; }
.points:hover { border-color: #2a3a44; background: rgba(255,255,255,.04); }
.points .sym { color: var(--gold); width: 1.2em; height: 1.2em; }
.points small { color: var(--faint); font-weight: 400; }
.tags { display: inline-flex; align-items: center; gap: 4px; color: var(--alert); font-weight: 700; }

/* Piles at table size: HQ, R&D and Archives on their racks; the stack, heap
   and score on the deck. Depth shows roughly how many cards are in them. */
.pile { display: inline-flex; flex-direction: column; align-items: center; gap: 3px; font-size: 12px; color: var(--dim); flex: none; }
button.pile { background: transparent; border: 0; padding: 0; }
.pile-cards { position: relative; width: var(--card-w); height: var(--card-h); }
.pile-top { position: absolute; inset: 0; border-radius: var(--r-card); background: #1a2533 center 28% / cover; border: 1px solid rgba(255,255,255,.12);
  box-shadow: calc(var(--depth) * 1px) calc(var(--depth) * 1px) 0 #06090c, calc(var(--depth) * 2px) calc(var(--depth) * 2px) 0 #04070a, var(--e1); }
.back-face { display: grid; place-items: center; background: repeating-linear-gradient(45deg, #11303a 0 5px, #0c2229 5px 10px); border-color: #23515a; color: var(--runner); }
.pile.corp .back-face { background: repeating-linear-gradient(45deg, #17262d 0 5px, #10191e 5px 10px); border-color: #2c4a40; color: var(--mat-ink); }
.back-face .sym { width: 42%; height: 42%; }
.pile.empty .pile-top { opacity: .3; box-shadow: none; border-style: dashed; }
.pile-label { margin-top: calc(var(--depth, 0) * 2px); white-space: nowrap; }
.pile-label b { color: var(--fg); }

/* Servers as racks in a row: a label plate, the server's own chassis with its
   cards, and its ICE mounted below as horizontal cards in their own chassis,
   outermost lowest and in front. Racks hold only chassis that carry cards.
   Under each rack is its gateway on Meridian's network. Empty racks are
   scenery. Rack details stay dark and still; the beacon lights only on the
   rack being run. */
.servers { position: relative; z-index: 2; display: flex; padding: 10px 14px 0; min-height: 0; }
/* Many remotes: the row fits by scaling the cards down first (--fit), then,
   past that floor, scrolls sideways with each rack still legible. The carousel
   view is the real answer for very large boards; this keeps it playable. */
.racks { flex: 1; min-width: 0; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(calc(var(--card-h) + 34px), 1fr); gap: clamp(6px, 1.1vw, 18px); align-items: stretch; overflow-x: auto; overflow-y: visible; scrollbar-width: thin; }
.server { position: relative; display: flex; flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; transition: opacity var(--t-slow) var(--ease-mech), filter var(--t-slow) var(--ease-mech); }
.rack { container-type: inline-size; position: relative; flex: 1; display: flex; flex-direction: column; gap: 4px; padding: 6px 12px; }
.rack > :not(.rackbg) { position: relative; z-index: 1; }
/* The rack's frame sits on its own layer so it can fade into the datacenter at
   the bottom, where the lower bays usually stand empty. The cards and ICE in
   front stay fully opaque; only the frame behind them dissolves, which opens
   that space up for the network nodes below to breathe. */
.rackbg { position: absolute; inset: 0; z-index: 0; border-radius: 4px; border: 1px solid #1a2f2b;
  background: repeating-linear-gradient(180deg, transparent 0 17px, rgba(26,46,41,.32) 17px 18px), linear-gradient(180deg, rgba(3,7,7,.6), rgba(1,3,3,.9));
  box-shadow: inset 0 1px 0 rgba(127,214,163,.16), 0 0 0 1px rgba(0,0,0,.7); transition: box-shadow var(--t-med);
  -webkit-mask-image: linear-gradient(to bottom, #000 58%, transparent); mask-image: linear-gradient(to bottom, #000 58%, transparent); }
.rackbg::before, .rackbg::after { content: ""; position: absolute; top: 5px; bottom: 5px; width: 4px; pointer-events: none;
  background: repeating-linear-gradient(180deg, #1a2e29 0 3px, transparent 3px 8px); }
.rackbg::before { left: 4px; } .rackbg::after { right: 4px; }
.plate { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 6px; min-height: 22px; padding: 0 4px 0 8px;
  border: 1px solid #1d332f; border-radius: 3px; background: rgba(0,0,0,.6); text-align: left; }
.plate b { min-width: 0; font: 700 10.5px var(--mono); letter-spacing: .1em; color: #e9f3ee; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* In a narrow rack the plate keeps the server's name and drops the rack number. */
@container (max-width: 210px) { .plate .rid { display: none; } }
.plate .readout { flex: none; font: 700 10px var(--mono); letter-spacing: .12em; color: var(--mat-ink); background: #020605; padding: 1px 6px; border-radius: 2px; box-shadow: inset 0 0 0 1px #10221e; }
.plate .readout i { font-style: normal; color: #4f7a6e; margin-right: 3px; }
.plate:hover { border-color: color-mix(in oklab, var(--mat-ink) 55%, #1d332f); }
.plate.playable { border-color: color-mix(in oklab, var(--runner) 30%, #1d332f); }
.beacon { position: absolute; top: -4px; right: -4px; width: 7px; height: 7px; border-radius: 50%; background: #1d2b28; box-shadow: 0 0 0 1px #000; }
.rack.target .beacon { background: var(--mat-light); box-shadow: 0 0 0 1px #000, 0 0 10px var(--mat-light); animation: beat 1s ease-in-out infinite alternate; }
@keyframes beat { to { opacity: .5; } }
.rack.target { box-shadow: inset 0 1px 0 rgba(217,164,65,.4), 0 0 0 1px rgba(217,164,65,.35), 0 0 30px rgba(217,164,65,.08); }
.server.selected .rack { box-shadow: inset 0 0 0 1px rgba(127,214,163,.45), 0 0 22px rgba(127,214,163,.08); }
/* An empty rack: rails and unit lines, nothing installed, no gateway. */
/* The rack carousel (wider screens). Every rack shares one grid cell, so the
   row is as tall as its tallest rack; Board's useRackCarousel then places each
   on a shallow ring with translate3d, sets its depth --d (1 at the front, -1
   at the back) and marks the front one. The camera sits a little above, so the
   back of the ring rises as it recedes. */
.racks.ring { display: grid; grid-template: 1fr / 1fr; overflow: visible; perspective: 1500px; perspective-origin: 50% -30%; padding-top: 16px; touch-action: pan-y; cursor: grab; user-select: none; }
.racks.ring.dragging { cursor: grabbing; }
.racks.ring > .rack-col { grid-area: 1 / 1; justify-self: center; align-self: end; width: calc(var(--card-h) + 40px); will-change: transform;
  opacity: calc((.4 + .6 * (var(--d, 1) + 1) / 2) * var(--fade, 1)); filter: brightness(calc(.62 + .38 * (var(--d, 1) + 1) / 2)) saturate(calc(.5 + .5 * (var(--d, 1) + 1) / 2)); }
.racks.ring > .rack-col.front .rackbg { border-color: color-mix(in oklab, var(--mat-ink) 30%, #1a2f2b); }
/* The turn buttons sit at the ends of the ring, over the datacenter. */
.turn { position: absolute; top: 50%; z-index: 120; translate: 0 -50%; width: 34px; height: 54px; padding: 0; border-radius: 10px; border: 1px solid #22423a;
  background: rgba(3,9,8,.72); color: var(--mat-ink); font: 700 24px/1 var(--mono); opacity: .55; transition: opacity var(--t-med), background var(--t-med); }
.turn:hover, .turn:focus-visible { opacity: 1; background: rgba(8,24,21,.9); }
.turn.left { left: 6px; } .turn.right { right: 6px; }

/* A chassis: a rack-mounted enclosure with ears, a vent, status lights and
   print too small to read. Dark and still; the card is the bright thing in it. */
.chassis { position: relative; flex: none; display: flex; align-items: center; gap: 10px; min-width: 0; padding: 4px 12px; border-radius: 3px;
  background: linear-gradient(180deg, #0c1413, #070c0b); box-shadow: inset 0 0 0 1px #172623, inset 0 1px 0 rgba(127,214,163,.08); }
.chassis::before, .chassis::after { content: ""; position: absolute; top: 3px; bottom: 3px; width: 6px; border-radius: 1px; pointer-events: none;
  background: radial-gradient(circle at 50% 9px, #000 0 1.6px, transparent 2px), radial-gradient(circle at 50% calc(100% - 9px), #000 0 1.6px, transparent 2px), #13201d; }
.chassis::before { left: 2px; } .chassis::after { right: 2px; }
.serverch { min-height: calc(var(--card-h) + 8px); }
.slotarea { position: relative; display: flex; flex: none; align-items: center; }
.slotarea .card + .card { margin-left: calc(var(--card-w) * -.55); }
.detail { flex: 1; min-width: 0; display: grid; gap: 6px; align-content: center; justify-items: start; overflow: hidden; }
.vent { width: 34px; height: 22px; border-radius: 2px; background: repeating-linear-gradient(90deg, #050908 0 2px, transparent 2px 5px); box-shadow: inset 0 0 0 1px #12201d; }
.leds { flex: none; display: grid; gap: 4px; }
.leds i { width: 4px; height: 4px; border-radius: 50%; background: #1d2b28; }
.leds i.g { background: #3f7f63; } .leds i.a { background: #8a6a2f; }
/* Decorative print: the shapes of words, too small to read at this distance. */
.micro { font: 700 3.6px/1.2 var(--mono); letter-spacing: .3em; color: #d9d3ca; opacity: .4; white-space: nowrap; text-transform: uppercase; pointer-events: none; }
.emptyroot { width: var(--card-w); text-align: center; color: var(--faint); font-size: 12px; font-style: italic; }
/* The card a run is accessing turns over where it sits. */
.card.revealed { animation: flipIn .6s var(--ease-out); }
@keyframes flipIn { from { transform: rotateY(90deg) scale(.85); filter: brightness(2); } }

/* ICE, each piece in its own chassis below the server's, outermost lowest.
   With three or more on one server, inner ICE tucks behind outer ICE with its
   title band showing. */
.icestack { margin-top: auto; display: flex; flex-direction: column; gap: 4px; }
.icech { min-height: calc(var(--card-w) + 6px); transition: box-shadow var(--t-med), opacity var(--t-med); }
/* The more ICE on one server, the harder they tuck, so even a deeply stacked
   server stays inside its rack with every title band still showing. Capped so
   at least a sliver of each card stays visible. */
.icestack.tight { --tuck: clamp(0.5, calc(0.5 + 0.055 * (var(--ice, 3) - 2)), 0.86); }
.icestack.tight .icech:not(:last-child) { margin-bottom: calc(var(--card-w) * -1 * var(--tuck)); }
.icestack .icech:nth-child(2) { z-index: 1; } .icestack .icech:nth-child(3) { z-index: 2; } .icestack .icech:nth-child(4) { z-index: 3; }
.icestack .icech:nth-child(5) { z-index: 4; } .icestack .icech:nth-child(6) { z-index: 5; }
.icech.passed { opacity: .5; }
.icech.facing { box-shadow: inset 0 0 0 1px var(--runner), 0 0 22px rgba(95,227,232,.35); }
.icech.encounter { box-shadow: inset 0 0 0 1px #ff6b7d, 0 0 26px rgba(255,107,125,.45); }
.icech.facing .leds i:first-child { background: var(--runner); box-shadow: 0 0 6px var(--runner); }
/* A piece of ICE is the full card turned on its side, its title and numbers
   laid out for that orientation: kind and title across the top, strength at
   the right, subtypes and subroutines along the bottom. */
.hcard { --kc: #ff7a8a; position: relative; flex: none; width: var(--card-h); height: var(--card-w); padding: 0; border-radius: var(--r-card); overflow: hidden;
  border: 1px solid rgba(255,255,255,.12); background: #1a1420; color: #fff; text-align: left; box-shadow: var(--e1); }
.hart { position: absolute; inset: 0; background: center 34% / cover; }
.htop { position: absolute; left: 0; right: 0; top: 0; display: flex; align-items: center; gap: 5px; padding: 4px 5px 12px 4px;
  background: linear-gradient(180deg, rgba(5,4,8,.94), rgba(5,4,8,.75) 60%, transparent); }
.kindchip { flex: none; display: grid; place-items: center; width: clamp(15px, calc(var(--card-w) * .23), 20px); height: clamp(15px, calc(var(--card-w) * .23), 20px);
  border-radius: 5px; background: rgba(0,0,0,.75); color: var(--kc); box-shadow: 0 0 0 1px var(--kc); }
.kindchip .kind-icon { width: 74%; height: 74%; }
.htitle { flex: 1; min-width: 0; padding-right: 2px; font-weight: 700; font-size: clamp(8.5px, calc(var(--card-w) * .135), 13px);
  line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-shadow: 0 1px 2px #000; }
.hstr { position: absolute; right: 4px; top: 52%; transform: translateY(-50%); display: grid; place-items: center; width: clamp(17px, calc(var(--card-w) * .27), 24px);
  height: clamp(20px, calc(var(--card-w) * .32), 28px); border-radius: 5px; background: var(--kc); color: #120a0c; font: 800 clamp(11px, calc(var(--card-w) * .17), 15px) var(--mono);
  box-shadow: 0 2px 6px rgba(0,0,0,.6); }
/* "STR" sits beside the badge, clear of the title. */
.hstr small { position: absolute; right: calc(100% + 3px); top: 50%; transform: translateY(-50%); font: 700 6.5px var(--mono); letter-spacing: .1em; color: #fff; opacity: .85; text-shadow: 0 1px 2px #000; }
.hbot { position: absolute; left: 0; right: 0; bottom: 0; display: flex; justify-content: space-between; align-items: end; gap: 6px; padding: 12px 6px 4px;
  background: linear-gradient(transparent, rgba(5,4,8,.9) 60%); font: 700 clamp(7px, calc(var(--card-w) * .1), 9px) var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--kc); }
.hkind { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.subs { flex: none; display: inline-flex; gap: 2px; color: #fff; opacity: .85; }
.subs i { width: 7px; height: 7px; border-left: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; border-radius: 0 0 0 2px; }
.subs i.broken { opacity: .25; }
.hcard.hidden { display: grid; place-content: center; justify-items: center; gap: 2px; background: repeating-linear-gradient(45deg, #17262d 0 6px, #10191e 6px 12px);
  border-color: #2c4a40; color: #9fc9b8; font: 700 10px var(--mono); letter-spacing: .14em; }
.hcard.hidden .kind-icon { width: 22px; height: 22px; }
.icech.arrive-rez .hcard { animation: rez .7s var(--ease-out); }
/* Each kind of ICE has a color, shared with the breaker badge that answers it and its login banner. */
.ice-barrier, .breaks-barrier { --kc: #ff9a52; }
.ice-codegate, .breaks-codegate { --kc: #6fa8ff; }
.ice-sentry, .breaks-sentry { --kc: #ff5f6d; }
.breaks-any { --kc: #5fe3e8; }
.icekind { position: relative; display: inline-grid; place-items: center; flex: none; }
.kind-icon { width: 18px; height: 18px; display: block; }

/* A gateway under each rack, where runs on that server start: select it to
   aim, then again to connect. */
.gate { position: relative; z-index: 3; align-self: center; flex: none; display: grid; place-items: center; width: 30px; height: 30px; padding: 0; border: 0; background: transparent; }
.gate .hex { width: 26px; height: 26px; display: grid; place-items: center; clip-path: polygon(25% 4%, 75% 4%, 100% 50%, 75% 96%, 25% 96%, 0 50%); background: #1d3a33; transition: background var(--t-med); }
.gate .hex::before { content: ""; width: 22px; height: 22px; clip-path: inherit; background: #030807; }
.gate .hex::after { content: ""; position: absolute; width: 6px; height: 6px; border-radius: 50%; background: var(--mat-ink); opacity: .7; }
.gwlbl { position: absolute; left: 30px; top: 50%; transform: translateY(-50%); white-space: nowrap; font: 9.5px var(--mono); letter-spacing: .04em; color: #4f7a6e; pointer-events: none; }
.gate:not(.idle):hover .hex, .gate:not(.idle):focus-visible .hex { background: var(--mat-ink); }
.gate:not(.idle):hover .gwlbl, .gate:focus-visible .gwlbl { color: var(--mat-ink); }
.gate.idle { cursor: default; }
.gate.idle .hex::after { opacity: .3; }
.gate.armed .hex { background: var(--runner); animation: hs 1s ease-out infinite; }
.gate.armed .hex::after, .gate.connected .hex::after { background: var(--runner); opacity: 1; }
.gate.connected .hex { background: var(--runner); }
.gate.armed .gwlbl, .gate.connected .gwlbl { color: var(--runner); }
@keyframes hs { 50% { filter: drop-shadow(0 0 8px var(--runner)); } }
.gate:focus-visible { outline: 2px solid var(--latch); outline-offset: 1px; border-radius: 50%; }

/* Meridian's network under the racks: the cores, the edge router and the
   house systems, dim scenery that runs travel along. */
.netband { height: clamp(46px, 7vh, 74px); }

/* A run reshapes the table: everything but the target steps back. */
.is-running .server:not(.running) { opacity: .28; filter: grayscale(.7); }
.is-running .row.grip { opacity: .55; }
.is-running .row.rig .card:not(.breaker) { opacity: .6; }

/* --- cards on the table ------------------------------------------------------ */
.card { position: relative; width: var(--card-w); height: var(--card-h); padding: 0; border: 0; background: transparent; border-radius: var(--r-card); flex: none;
  transition: transform var(--t-med) var(--ease-spring), opacity var(--t-med); }
.face { position: absolute; inset: 0; border-radius: var(--r-card); overflow: hidden; background: #1a2230 center 28% / cover; box-shadow: var(--e1);
  border: 1px solid rgba(255,255,255,.09); text-align: left; transition: box-shadow var(--t-med) var(--ease-out); }
.face .top { position: absolute; left: 0; right: 0; top: 0; padding: 5px 6px 16px;
  background: linear-gradient(180deg, rgba(4,6,9,.94) 0%, rgba(4,6,9,.82) 55%, transparent); }
/* The cost coin hangs off the top-left corner, outside the art, like a coin set on the card. */
.card > .cost { position: absolute; z-index: 5; top: -7px; left: -7px; display: grid; place-items: center; pointer-events: none;
  width: clamp(17px, calc(var(--card-w) * .22), 24px); height: clamp(17px, calc(var(--card-w) * .22), 24px); border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffe08a, var(--gold) 60%, #b98a2a); color: #141006; font-family: var(--mono); font-weight: 700;
  font-size: clamp(9.5px, calc(var(--card-w) * .13), 13.5px); box-shadow: 0 0 0 1.5px #0b0f13, 0 2px 5px rgba(0,0,0,.6); }
.card > .cost + .face .top { padding-left: clamp(11px, calc(var(--card-w) * .16), 18px); }
.face .name { font-size: clamp(8.5px, calc(var(--card-w) * .13), 13.5px); font-weight: 700; line-height: 1.12; letter-spacing: -.01em; text-shadow: 0 1px 2px #000;
  hyphens: auto; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.face .foot { position: absolute; left: 0; right: 0; bottom: 0; padding: 12px 6px 4px; background: linear-gradient(transparent, rgba(4,6,9,.88) 60%);
  font-size: clamp(8.5px, calc(var(--card-w) * .1), 11px); font-weight: 700; color: var(--tc); text-transform: uppercase; letter-spacing: .06em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card:hover .face, .card:focus-visible .face { box-shadow: var(--e2); }
.card.playable .face { box-shadow: 0 0 0 1px color-mix(in oklab, var(--runner) 45%, transparent), var(--e1); }
.card.playable:hover .face { box-shadow: 0 0 0 1px color-mix(in oklab, var(--runner) 65%, transparent), var(--e2); }
.card.selected .face { box-shadow: 0 0 0 2px var(--latch-mark), var(--e2); }
/* The rig's cards lift a little; Meridian's cards stay put, since you'd never pick them up. */
.row.rig .card:hover, .row.rig .card:focus-visible, .row.rig .card.selected { transform: translateY(-6px); z-index: 3; }
.back { position: absolute; inset: 0; border-radius: var(--r-card); background: repeating-linear-gradient(45deg, #17262d 0 7px, #10191e 7px 14px); border: 1px solid #2c4a40;
  box-shadow: var(--e1); display: grid; place-items: center; font-size: 11px; color: color-mix(in oklab, var(--mat-ink) 70%, white); }
.facedown .adv { position: absolute; bottom: 6px; left: 0; right: 0; display: flex; justify-content: center; gap: 1px; color: var(--gold); }
/* A breaker wears the icon of the ICE it breaks, on its left edge so it shows in a fanned hand. */
.breaks { position: absolute; left: 4px; top: 44%; width: clamp(18px, calc(var(--card-w) * .24), 24px); height: clamp(18px, calc(var(--card-w) * .24), 24px);
  border-radius: var(--r-chip); display: grid; place-items: center; z-index: 4; background: #0a0f14; color: var(--kc); box-shadow: 0 0 0 1.5px var(--kc), 0 2px 6px rgba(0,0,0,.6); }
.breaks .kind-icon { width: 70%; height: 70%; }
.latchmark { position: absolute; top: -10px; right: -6px; background: var(--latch-mark); color: #0b1418; font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 99px; letter-spacing: .04em; z-index: 4; }
.move .latchmark { position: static; margin-left: 6px; }

/* arrivals */
.arrive-draw { animation: drawIn .5s var(--ease-spring); }
@keyframes drawIn { from { translate: 60px 40px; rotate: 8deg; opacity: 0; } }
.arrive-install { animation: installIn .45s var(--ease-out); }
@keyframes installIn { from { translate: 0 70px; scale: .85; opacity: .2; } }
.arrive-rez { animation: rez .7s var(--ease-out); }
.ice.arrive-rez::after { content: ""; position: absolute; inset: -4px; border-radius: 9px; border: 2px solid var(--kc, #ff7a8a); animation: rezping .9s ease-out forwards; }
@keyframes rezping { from { opacity: 1; transform: scale(.9); } to { opacity: 0; transform: scale(1.25); } }
@keyframes rez { from { transform: rotateX(90deg); filter: brightness(2.5); } 60% { filter: brightness(1.4); } }
.bump { animation: bump .45s var(--ease-out); }
@keyframes bump { 30% { transform: scale(1.35); } }

/* --- Catalyst's deck ----------------------------------------------------------- */
/* The secondhand cyberdeck, a physical thing in the room: warm graphite
   casing, warm grey keys, and cyan only where it glows (Latch AI's screen,
   LEDs, the uplink). A status bar along its top edge, Latch's screen on the
   left, the rig's bays, stack and heap and the fanned grip in the middle, and
   the key bed along the bottom. One device, not a tiled pattern. */
.runner-mat { position: relative; min-height: 0; margin: 0 10px; border-radius: 20px 20px 0 0;
  background: radial-gradient(120% 140% at 50% 0%, #2a2724 0%, #1d1b19 45%, #161413 100%);
  border: 1px solid #3a3531; border-bottom: 0;
  box-shadow: inset 0 1px 0 rgba(255,236,214,.09), inset 0 0 0 1px rgba(0,0,0,.45), 0 -18px 40px rgba(0,0,0,.75); }
.runner-mat .crack { position: absolute; right: 0; bottom: 0; width: 220px; height: 140px; background: url(/art/secondhand-crack.svg) no-repeat; transform: scaleX(-1);
  pointer-events: none; z-index: 1; opacity: .8; }
/* The uplink, where runs leave the deck: an RJ45 port in its top edge. */
.uplink { position: absolute; left: 50%; top: -9px; transform: translateX(-50%); z-index: 3; width: 40px; height: 20px; border-radius: 3px 3px 5px 5px;
  display: grid; place-items: end center; padding-bottom: 3px; background: #0b0a0a; box-shadow: inset 0 0 0 1px #4a443f, inset 0 -6px 0 #151312, 0 2px 0 #0a0909; }
.uplink i { width: 16px; height: 5px; border-radius: 1px; background: #2a2724; }
/* The casing's edges: current-day hardware, kept quiet. */
.edges > * { position: absolute; z-index: 2; pointer-events: none; }
.usbc { top: -3px; width: 22px; height: 7px; border-radius: 4px; background: #0b0a0a; box-shadow: inset 0 0 0 1px #3c3732, inset 0 1px 0 #000; }
.usbc::after { content: ""; position: absolute; left: 5px; right: 5px; top: 3px; height: 1px; background: #4a443f; }
.vents { top: -1px; right: 72px; width: min(220px, 18%); height: 6px; border-radius: 0 0 3px 3px; opacity: .9; background: repeating-linear-gradient(90deg, #0d0c0b 0 14px, transparent 14px 20px); }
.screw { width: 9px; height: 9px; border-radius: 50%; background: radial-gradient(circle at 40% 35%, #5a544e, #2a2724 70%); box-shadow: 0 0 0 1px #0d0c0b; }
.screw::after { content: ""; position: absolute; inset: 2.5px; background: #141210; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); }
.screw.tl { left: 6px; top: 6px; } .screw.tr { right: 6px; top: 6px; } .screw.bl { left: 6px; bottom: 6px; } .screw.br { right: 6px; bottom: 6px; }
.uplink.live i { background: var(--runner); box-shadow: 0 0 10px var(--runner), 0 0 22px var(--runner); animation: live 1s ease-in-out infinite alternate; }
@keyframes live { to { opacity: .55; } }
.strip.runner { border-radius: 20px 20px 0 0; padding-left: 18px; background: linear-gradient(180deg, rgba(52,48,44,.55), rgba(30,28,26,.15)); border-bottom: 1px solid #2e2a27; }
.deck-face { position: relative; z-index: 2; display: grid; grid-template-columns: minmax(250px, 300px) minmax(0, 1fr); grid-template-rows: auto auto auto;
  grid-template-areas: "screen rig" "screen grip" "keys keys"; gap: 6px 16px; padding: 8px 14px 10px; }

/* Latch AI's screen, set into the deck. Names it mentions are live: hover or
   focus one and Latch points at it on the table; select it to open it. */
.latch-screen { grid-area: screen; align-self: stretch; min-height: 0; max-height: calc(var(--card-h) * 2.6); display: grid; grid-template-rows: auto minmax(0, 1fr) auto; gap: 4px;
  border-radius: var(--r-panel); padding: 8px 10px 10px; background: radial-gradient(120% 90% at 30% 0%, #0f2428, #071113 70%); border: 1px solid #3c3732;
  box-shadow: inset 0 0 0 3px #0f0e0d, inset 0 0 26px rgba(95,227,232,.08), 0 0 0 1px rgba(0,0,0,.5), var(--e1); }
.latch-screen.touring { border-color: var(--latch); box-shadow: inset 0 0 0 3px #0f0e0d, 0 0 24px rgba(95,227,232,.18), var(--e1); }
.screen-head { display: flex; align-items: center; gap: 8px; font-size: 12px; min-width: 0; }
.screen-head b { color: var(--latch); letter-spacing: .06em; }
.screen-status { flex: 1; min-width: 0; color: var(--dim); font: 11.5px var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.screen-toggle { position: relative; background: transparent; border: 1px solid #23434a; border-radius: var(--r-chip); color: var(--dim); font-size: 11.5px; padding: 1px 8px; }
.screen-toggle:hover { color: var(--fg); }
.screen-toggle .unread { position: absolute; top: -3px; right: -3px; width: 8px; height: 8px; border-radius: 50%; background: var(--latch); box-shadow: 0 0 6px var(--latch); }
.screen-body { min-height: 0; overflow: auto; padding: 2px 2px 4px; }
.screen-body p { margin: 0 0 6px; font-size: 14px; line-height: 1.45; }
.screen-body .screen-more { color: var(--dim); font-size: 13px; border-left: 2px solid #26474c; padding-left: 8px; }
.screen-body .idle { color: var(--faint); font-size: 13px; }
.screen-keys { display: flex; flex-wrap: wrap; gap: 6px; }
.mention { display: inline; padding: 0 2px; margin: 0 -2px; border: 0; border-radius: 4px; background: transparent; color: var(--latch-mark); font: inherit; font-weight: 700;
  text-decoration: underline dotted rgba(244,247,251,.6); text-underline-offset: 3px; }
.mention:hover, .mention:focus-visible { background: rgba(244,247,251,.12); text-decoration-style: solid; }

/* The rig: an M.2 module seated in its socket on the deck's mainboard, seen
   through a bay in the casing. No chips; its print is too small to read, and
   only the bay names stenciled on the module are legible. */
.row { display: flex; gap: 8px; align-items: center; min-width: 0; position: relative; z-index: 2; transition: opacity var(--t-med); border-radius: 10px; }
.row.rig { grid-area: rig; align-items: stretch; }
.row.grip { grid-area: grip; align-items: flex-end; }
.row.tour { box-shadow: inset 0 0 0 2px var(--latch); }
.rowlabel { flex: none; align-self: center; writing-mode: vertical-rl; transform: rotate(180deg); font: 700 10px var(--mono); letter-spacing: .2em; color: #6f665f; }
.rigbay { position: relative; flex: 1; min-width: 0; display: flex; align-items: stretch; padding: 4px 14px 4px 18px; border-radius: 10px; overflow-x: auto; overflow-y: hidden;
  background: radial-gradient(120% 140% at 30% 0%, #10201a, #0c1411 60%), #0c1411; box-shadow: inset 0 0 0 1px #2e2a26, inset 0 4px 10px rgba(0,0,0,.7); }
.pcb { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; }
.pcb path { fill: none; stroke: #13241d; stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.pcb circle { fill: #0a120f; stroke: #1c3328; stroke-width: 1; vector-effect: non-scaling-stroke; }
/* The socket: a black molded body with its key, and gold legs soldered to the board. */
.socket { position: relative; z-index: 1; flex: none; width: 30px; margin-right: -4px; }
.socket .body { position: absolute; left: 7px; top: 0; bottom: 0; width: 20px; border-radius: 3px; background: linear-gradient(90deg, #1b1b1d, #101012 60%, #19191b);
  box-shadow: inset 0 0 0 1px #2a2a2d, 0 3px 6px rgba(0,0,0,.6); }
.socket .body::before { content: ""; position: absolute; left: 4px; right: 4px; top: 22%; height: 4px; border-radius: 2px; background: #060607; }
.socket .legs { position: absolute; left: 0; width: 8px; background: repeating-linear-gradient(180deg, #c9a24a 0 1.5px, transparent 1.5px 3.6px); }
.socket .legs.a { top: 3%; height: 16%; } .socket .legs.b { top: 28%; bottom: 3%; }
.socket .micro { position: absolute; left: 9px; top: 34%; transform: rotate(90deg); transform-origin: left top; color: #6c6c70; }
.module { position: relative; z-index: 1; flex: none; min-width: max-content; display: flex; align-items: center; gap: 18px; padding: 4px 168px 4px 22px; border-radius: 0 9px 9px 0;
  background: linear-gradient(180deg, #121514, #0c0e0d); box-shadow: 0 0 0 1px #1f2321, 0 8px 18px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05); }
.module .notch { position: absolute; right: -1px; top: 50%; width: 26px; height: 26px; margin-top: -13px; border-radius: 50% 0 0 50%; background: #0c1411; box-shadow: inset 1px 0 0 #1f2321; }
.standoff { position: absolute; z-index: 2; right: 6px; top: 50%; width: 20px; height: 20px; margin-top: -10px; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #8f8577, #4e4740 70%); box-shadow: 0 0 0 3px #0c0e0d; }
.standoff::after { content: ""; position: absolute; inset: 5px; background: #1b1816; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); }
.module .micro.m1 { position: absolute; right: 64px; top: 10px; }
.module .micro.m3 { position: absolute; right: 64px; top: 21px; }
.module .micro.m2 { position: absolute; right: 64px; bottom: 10px; }
/* The bay names, stenciled on the module itself in white silkscreen. */
.silk { font: 700 8.5px var(--mono); letter-spacing: .16em; color: #d9d3ca; text-transform: uppercase; white-space: nowrap; }
/* The bay name is a thin stencil to the left of its cards, reading bottom to
   top, so the module is a card tall and no more and the datacenter above it
   gets those pixels back. The memory LEDs sit level under the Programs name. */
.mbay { display: flex; align-items: stretch; gap: 10px; min-width: 0; }
/* The bay names are screenprinted straight onto the module: no frame. */
.mbay-label { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; flex: none; padding: 2px; opacity: .5; }
.mbay-name { writing-mode: vertical-rl; transform: rotate(180deg); }
.slots { display: flex; gap: 16px; align-items: center; min-height: var(--card-h); }
/* Each slot is a card socket: the runner's cards read as removable memory
   modules clicked into the board, so the sockets alone make the point and the
   cards stay exactly as they are elsewhere. A card lifts out of its socket on
   hover; the socket well stays put. */
.sock { position: relative; flex: none; width: var(--card-w); height: var(--card-h); }
.sock::before { content: ""; position: absolute; left: -5px; right: -5px; top: -4px; bottom: -10px; border-radius: 3px;
  background: linear-gradient(180deg, #0a0d0c, #050706); box-shadow: inset 0 0 0 1px #1b231f, inset 0 3px 6px rgba(0,0,0,.85), inset 0 -2px 3px rgba(0,0,0,.6); }
/* A contact lip at the mouth of the socket, and two guide notches on the sides. */
.sock::after { content: ""; position: absolute; left: 24%; right: 24%; bottom: -8px; height: 3px; border-radius: 1px; background: #14433a; box-shadow: 0 0 5px rgba(79,154,119,.4); }
.sock > .card { position: relative; z-index: 1; }
.sock.empty::before { background: linear-gradient(180deg, #0b0e0d, #070908); }
.sock.empty::after { background: #122a26; box-shadow: none; }
/* A thin label inside an empty socket, so the bay still reads at a glance. */
.sock.empty { opacity: .9; }

/* The grip: held cards, fanned in a shallow arc. The card you're over rises
   to full view; nothing changes size. */
.hand { flex: 1; min-width: 0; display: flex; justify-content: center; align-items: flex-end; padding: 12px 6px 6px; }
/* Cards overlap a little for the look, and more only when the row runs out of
   room: the row is a size container, so the overlap follows its width. */
.row.grip { container-type: inline-size; }
.hand .card { transform: translateY(var(--dy, 0px)) rotate(var(--rot, 0deg)); transform-origin: 50% 120%; z-index: var(--z, 1);
  margin-left: calc(-1 * max(var(--card-w) * var(--ov, .06), (var(--card-w) * var(--n, 1) - (100cqw - 48px)) / max(1, var(--n, 1) - 1))); }
.hand .card:first-child { margin-left: 0; }
.hand .card:hover, .hand .card:focus-visible, .hand .card.selected { transform: translateY(calc(var(--card-h) * -.14)) rotate(0deg); z-index: 60; }
.emptyrow { color: #7a7068; font-style: italic; font-size: 13px; padding-bottom: 20px; }

/* The stack, heap and score, at the end of the rig's row. */
.deck-side { margin-left: auto; display: flex; gap: 10px; align-items: flex-start; flex: none; padding-left: 12px; }
.deck-side .back-face .sym { display: none; }
/* The key bed is the deck's terminal at the bottom of the visible deck. The
   session log fills it, reporting only (no cursor; nothing is typed here), and
   the action buttons dock at its bottom-right as flat TUI buttons. There is no
   physical keyboard on screen: it sits below the deck's visible edge. */
.deck-keys { grid-area: keys; min-width: 0; }
.keybed { padding: 7px 12px 8px 14px; border-radius: 12px;
  background: linear-gradient(180deg, #0b0a09, #12100f); border: 1px solid #2b2724; box-shadow: inset 0 3px 8px rgba(0,0,0,.7), inset 0 -1px 0 rgba(255,236,214,.05); }
.term { position: relative; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.slog { position: relative; flex: none; height: calc(11px * 1.3 * 3.4); overflow: hidden; display: flex; flex-direction: column; justify-content: flex-end; font: 11px/1.3 var(--mono); color: #8a8178;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 12px); mask-image: linear-gradient(to bottom, transparent, #000 12px); }
.ln { flex: none; white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.ln .ps { color: var(--runner); }
.ln.cmd { color: #e8e2db; }
.ln.dbg { color: #6b635c; }
.ln.ok { color: var(--mat-ink); }
.ln.warn { color: var(--mat-light); }
.ln.err { color: #ff6b6b; }
.ln.int { color: #ff6b6b; font-weight: 700; animation: flash .14s steps(2) 3; }
@keyframes flash { 50% { background: rgba(255,107,107,.28); } }
.ln.ready { color: #a99f95; }
.ln.plain { color: #cfc8c0; }
.ln i { font-style: normal; color: #6b635c; }
/* The login banner a piece of ICE puts up: imposing, in its kind's color, hugging its text. */
.banner { --kc: #ff7a8a; flex: none; align-self: flex-start; max-width: 100%; margin: 2px 0 1px; border: 1px solid var(--kc); border-radius: 3px; overflow: hidden;
  box-shadow: 0 0 18px color-mix(in oklab, var(--kc) 22%, transparent); }
.banner.ice-barrier { --kc: #ff9a52; } .banner.ice-codegate { --kc: #6fa8ff; } .banner.ice-sentry { --kc: #ff5f6d; }
.banner .bh { padding: 1px 8px; background: var(--kc); color: #0d0b0b; font-weight: 800; letter-spacing: .16em; white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.banner .bl { padding: 0 8px; color: #efe9e2; white-space: pre; overflow: hidden; text-overflow: ellipsis; }
.banner .bh + .bl { padding-top: 1px; }
.banner .bl:last-child { padding-bottom: 2px; }
.banner .bl.dim { color: #a8a099; }
.prog { flex: none; display: flex; align-items: center; gap: 10px; color: #e8e2db; white-space: pre; }
.prog .bar { width: 200px; height: 8px; border: 1px solid #3a3530; border-radius: 2px; background: #141210; overflow: hidden; }
.prog .bar i { display: block; height: 100%; background: linear-gradient(90deg, #4f9a77, var(--mat-ink)); }
/* The moves are command options in the deck's terminal, typed out in its
   own text: "[1] Mulligan (once)". No button chrome: the deck's keyboard sits
   below the view, so the screen only lists what the keys do. They are still
   buttons underneath, for pointer, touch, keyboard and screen readers. */
.keyset { flex: none; display: flex; flex-wrap: wrap; justify-content: flex-start; align-items: baseline; gap: 2px 18px; min-height: 26px;
  font: 12.5px/1.5 var(--mono); }
.keyset::before { content: "›"; color: var(--latch); margin-right: -8px; }
.keys-idle { color: var(--faint); font: 12px var(--mono); }
.keycap { position: relative; display: inline-flex; align-items: baseline; gap: 6px; min-width: 0; max-width: 44ch; padding: 1px 4px; margin: 0 -4px;
  text-align: left; font: inherit; color: #e7e1d9; background: none; border: 0; border-radius: 2px; }
.keycap .legend { flex: none; color: var(--gold); font-weight: 700; }
.keycap .legend::before { content: "["; color: #6c665d; font-weight: 400; }
.keycap .legend::after { content: "]"; color: #6c665d; font-weight: 400; }
.keycap .cap { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.keycap:hover:not(:disabled), .keycap:focus-visible { background: #e7e1d9; color: #11140f; outline: none; }
.keycap:hover:not(:disabled) .legend, .keycap:focus-visible .legend { color: #6b4a00; }
.keycap:active:not(:disabled) { background: var(--gold); }
.keycap:disabled { opacity: .4; }
.keycap.hint { box-shadow: inset 0 -2px 0 var(--latch-mark); }
.keycap.hint::after { content: "◂ latch"; margin-left: 4px; font-size: 11px; color: var(--latch-mark); opacity: .8; }
.keycap.hint:hover::after, .keycap.hint:focus-visible::after { color: #11140f; }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* --- moves beside a card being read --------------------------------------------- */
@keyframes up { from { transform: translateY(16px); opacity: 0; } }
.moves { display: flex; flex-wrap: wrap; gap: 8px; }
.move { background: #1b2735; border: 1px solid #2d3d52; border-radius: 9px; padding: 7px 12px; font-weight: 700; font-size: 13.5px; display: inline-flex; align-items: center; gap: 8px;
  box-shadow: 0 3px 0 #0b121a; transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out), background var(--t-fast); }
.move:hover:not(:disabled) { background: #22324a; }
.move:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 #0b121a; }
.move:disabled { opacity: .45; }
.move .key { font: 700 11px var(--mono); color: var(--gold); }
.move.hint { border-color: var(--latch-mark); }

/* --- overlays: trace, pointer, callouts, reveal, bursts --------------------- */
.fx-layer { position: absolute; inset: 0; pointer-events: none; z-index: 6; }
/* A stolen agenda digitizing: its art breaks into blocks that light from the
   bottom up, then peel off toward the uplink to enter the wire. */
.digitize { position: absolute; inset: 0; pointer-events: none; z-index: 9; }
.dgb { position: absolute; border-radius: 1px; opacity: 0; background-repeat: no-repeat;
  box-shadow: 0 0 5px rgba(125,255,176,.5), inset 0 0 0 1px rgba(125,255,176,.22);
  animation: dgblock .62s cubic-bezier(.3,.1,.5,1) forwards; }
@keyframes dgblock {
  0% { opacity: 0; transform: translate(0, 0) scale(1); }
  14% { opacity: 1; filter: brightness(1.4) saturate(1.2); }
  100% { opacity: 0; transform: translate(var(--tx, 0), var(--ty, -40px)) scale(.3); filter: brightness(2.2); }
}
/* Latch AI's marker rides above every panel, so it's never hidden behind the one it points into. */
.pointer-layer { position: absolute; inset: 0; pointer-events: none; z-index: 11; }
.fx-svg { position: absolute; left: 0; top: 0; overflow: visible; }
.trace-glow, .trace-core, .trace-flow, .trace-preview { stroke-linejoin: round; stroke-linecap: round; }
.trace-glow { fill: none; stroke-width: 12; opacity: .22; filter: blur(4px); }
.trace-core { fill: none; stroke-width: 2.5; opacity: .9; }
.trace-flow { fill: none; stroke-width: 2; stroke-dasharray: 3 18; opacity: .85; animation: flow .9s linear infinite; }
/* A gateway aimed at but not yet connected to: the route, dashed. */
.trace-preview { fill: none; stroke-width: 1.6; stroke-dasharray: 3 5; opacity: .65; animation: fadein .5s ease-out backwards; }
/* The surfaced route's hops and dead-end branches: they pop in hop by hop
   when the route is new, and the branches dim once it's drawn. */
.route-hop { animation: hop-in .24s ease-out backwards; transform-box: fill-box; transform-origin: center; }
.route-hop rect { fill: #030807; stroke: var(--hc, #5fe3e8); stroke-width: 1.4; }
.route-hop text, .route-spur text { font: 10px var(--mono); letter-spacing: .04em; paint-order: stroke; stroke: #020403; stroke-width: 3px; }
.route-hop text { fill: color-mix(in oklab, var(--hc, #5fe3e8) 70%, #cfe9e2); }
.route-spur { animation: fadein .3s ease-out backwards, route-dim 1.2s ease-out forwards; }
.route-spur path { fill: none; stroke: #3c7a6a; stroke-width: 1.2; stroke-dasharray: 1; animation: route-draw .3s ease-out backwards; }
.route-spur rect { fill: #030807; stroke: #3c7a6a; stroke-width: 1.2; }
.route-spur text { fill: #5f8e80; }
@keyframes hop-in { from { opacity: 0; transform: scale(.4); } }
@keyframes fadein { from { opacity: 0; } }
@keyframes route-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes route-dim { to { opacity: .3; } }
/* Inside the server, the flow pulls back toward the deck. */
.trace-flow.back { animation-direction: reverse; animation-duration: .6s; }
.trace-done { animation: tracefade 1.8s ease-in forwards; }
@keyframes tracefade { 0%, 55% { opacity: 1; } 100% { opacity: 0; } }
.packet rect { filter: drop-shadow(0 0 8px currentColor); }
@keyframes flow { to { stroke-dashoffset: -21; } }
.trace-end { fill: none; stroke-width: 2; animation: ring 1.4s ease-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes ring { from { transform: scale(.6); opacity: 1; } to { transform: scale(1.7); opacity: 0; } }
.spark { animation: spark .7s ease-out forwards; }
@keyframes spark { to { transform: translate(var(--dx), var(--dy)); opacity: 0; } }
.install-core { fill: none; stroke: color-mix(in oklab, var(--mat-ink) 60%, transparent); stroke-width: 1.5; }
.install-flow { fill: none; stroke: var(--mat-ink); stroke-width: 2; stroke-dasharray: 3 12; animation: flow .8s linear infinite; }
.install-end { fill: none; stroke: var(--mat-ink); stroke-width: 1.5; animation: ring 1.2s ease-out infinite; transform-box: fill-box; transform-origin: center; }
.install-link { animation: installfade 3.6s ease-in forwards; }
@keyframes installfade { 0% { opacity: 0; } 10%, 70% { opacity: 1; } 100% { opacity: 0; } }
/* Latch AI pointing: a white tag with Latch's face and an arrow, bobbing. It
   shares nothing with the table's own highlights. */
.latch-pointer { position: absolute; z-index: 9; transform: translate(-50%, -100%); display: grid; justify-items: center; pointer-events: none; animation: bob 1.1s ease-in-out infinite; }
.latch-pointer.below { transform: translate(-50%, 0); animation-name: bobdown; }
.latch-pointer.below .lp-arrow { order: -1; transform: rotate(180deg); }
.lp-chip { display: inline-flex; align-items: center; gap: 5px; background: var(--latch-mark); color: #0b1418; font: 700 11px var(--ui); padding: 2px 8px 2px 5px; border-radius: 99px; box-shadow: 0 4px 12px rgba(0,0,0,.6); }
.lp-chip .avatar rect:not(.eye) { fill: #0b6b70; }
.lp-arrow { display: block; margin-top: -1px; filter: drop-shadow(0 3px 4px rgba(0,0,0,.6)); }
.lp-arrow path { fill: var(--latch-mark); }
@keyframes bob { 50% { margin-top: -6px; } }
@keyframes bobdown { 50% { margin-top: 6px; } }
/* Tooltips. */
.tip { position: fixed; z-index: 40; transform: translate(-50%, -100%); max-width: 260px; background: #eef2f6; color: #0b1418; font-size: 12.5px; line-height: 1.35;
  padding: 6px 10px; border-radius: 8px; box-shadow: var(--e3); pointer-events: none; animation: tipin var(--t-fast) ease-out; }
.tip.below { transform: translate(-50%, 0); }
@keyframes tipin { from { opacity: 0; } }
.callout { position: absolute; transform: translate(-50%, -110%); background: rgba(10,18,20,.95); border: 1px solid color-mix(in oklab, var(--mat-ink) 55%, #1d2b35);
  color: var(--fg); font-size: 12.5px; padding: 4px 10px; border-radius: 8px; white-space: nowrap; box-shadow: var(--e3); animation: callout 4.2s ease-out forwards; }
.callout.corner { font-size: 12px; opacity: .92; }
@keyframes callout { 0% { opacity: 0; transform: translate(-50%, -80%); } 10%, 80% { opacity: 1; transform: translate(-50%, -110%); } 100% { opacity: 0; transform: translate(-50%, -130%); } }
.burst { position: absolute; left: 50%; bottom: 22%; transform: translateX(-50%); display: grid; place-items: center; }
.burst-card { width: var(--card-w); height: var(--card-h); border-radius: var(--r-card); background: center 28% / cover; box-shadow: 0 0 0 2px var(--bc), 0 0 40px var(--bc); animation: rise 1.5s var(--ease-out) forwards; }
@keyframes rise { 0% { transform: translateY(80px); opacity: 0; } 25% { transform: translateY(0); opacity: 1; } 70% { opacity: 1; } 100% { transform: translateY(-90px); opacity: 0; filter: brightness(1.8); } }
.burst-ring { position: absolute; width: 60px; height: 60px; border-radius: 50%; border: 2px solid var(--bc); animation: ringout 1.2s .35s ease-out forwards; opacity: 0; }
@keyframes ringout { from { transform: scale(.5); opacity: .9; } to { transform: scale(5); opacity: 0; } }
.burst-title { position: absolute; bottom: -24px; font-weight: 700; color: var(--bc); animation: rise 1.5s var(--ease-out) forwards; }

/* --- reading a card: the printed card over the rig -------------------------- */
.review { position: absolute; z-index: 10; --pw: calc(var(--ph) * .714); --rw: calc(var(--pw) + 300px); width: var(--rw);
  display: grid; grid-template-columns: var(--pw) minmax(0, 1fr); gap: 14px; align-items: end; animation: lift var(--t-med) var(--ease-out); }
@keyframes lift { from { transform: translateY(30px); opacity: 0; } }
.review-side { position: relative; background: rgba(8,14,18,.96); border: 1px solid #1d3a3e; border-radius: var(--r-panel); padding: 14px 16px; display: grid; gap: 10px;
  box-shadow: var(--e3); }
.review-side .close { position: absolute; top: 4px; right: 8px; background: transparent; border: 0; color: var(--dim); font-size: 22px; }
.review-side .teach { margin: 0 18px 0 0; color: var(--dim); font-size: 13.5px; }
.review-side .credit { margin: 0; color: var(--faint); font-size: 11.5px; }
.review-side .none { margin: 0; color: var(--faint); font-size: 13px; }

/* The printed card. Original Board design; sizes scale with its height. */
.printed { --edge: color-mix(in oklab, var(--tone) 65%, #000); position: relative; overflow: hidden; height: var(--ph); width: var(--pw);
  font-size: calc(var(--ph) / 34); border-radius: calc(var(--ph) * .035); padding: .6em; display: grid; grid-template-rows: auto minmax(0, 1fr) auto auto auto; gap: .4em;
  background: linear-gradient(160deg, #13202a, #0a1015 70%); border: 2px solid var(--edge); color: var(--fg);
  box-shadow: 0 0 0 1px rgba(0,0,0,.6), var(--e3), 0 0 44px color-mix(in oklab, var(--tone) 22%, transparent); }
.printed.side-corp { background: linear-gradient(160deg, #18201f, #0b100f 70%); }
.pc-head { display: flex; align-items: center; gap: .45em; padding: .3em .45em; border-radius: .4em;
  background: linear-gradient(90deg, color-mix(in oklab, var(--tone) 30%, #0b1116), #0b1116 85%); border-bottom: 1px solid var(--edge); }
.pc-head h3 { margin: 0; flex: 1; font-size: 1.3em; line-height: 1.1; }
.pc-cost, .pc-adv { display: inline-flex; align-items: center; gap: .15em; color: var(--gold); font-size: 1.25em; }
.pc-cost .sym, .pc-adv .sym { width: 1em; height: 1em; }
.pc-kind { width: 1.9em; height: 1.9em; display: grid; place-items: center; border-radius: .35em; background: rgba(0,0,0,.5); color: var(--tone); box-shadow: 0 0 0 1px var(--tone); }
.pc-kind .kind-icon { width: 1.25em; height: 1.25em; }
.pc-art { min-height: 0; background: #1a2230 center / cover; border-radius: .35em; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), 0 0 0 1px var(--edge); }
.pc-type { font: 700 .72em var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--tone); }
.pc-type span { color: var(--dim); }
.pc-type .pc-like { font: 400 1.05em var(--ui); letter-spacing: 0; text-transform: none; }
.pc-text { min-height: 5.6em; padding: .5em .65em; border-radius: .35em; background: rgba(4,7,9,.62); border: 1px solid #1c2830; font-size: .95em; line-height: 1.35; }
.pc-text p { margin: 0 0 .35em; }
.pc-text p:last-child { margin-bottom: 0; }
.pc-text p.sub { display: flex; gap: .4em; }
.pc-text .sym { flex: none; margin-top: .18em; color: var(--tone); }
.pc-text .none { color: var(--faint); }
.pc-foot { display: flex; align-items: center; gap: .5em; font-size: .85em; min-height: 2.2em; }
.pc-set { flex: 1; text-align: center; color: var(--faint); font: .72em var(--mono); letter-spacing: .06em; }
.pc-str, .pc-trash { display: inline-grid; justify-items: center; line-height: 1; padding: .25em .55em; border-radius: .35em;
  background: color-mix(in oklab, var(--tone) 22%, #0b1116); border: 1px solid var(--edge); }
.pc-str b, .pc-trash b { font-size: 1.6em; }
.pc-str small, .pc-trash small { font: 700 .62em var(--mono); letter-spacing: .1em; color: var(--dim); }
.pc-mu, .pc-points { display: inline-flex; align-items: center; gap: .2em; font-size: 1.25em; font-weight: 700; }
.pc-mu { color: var(--runner); } .pc-points { color: var(--gold); }
.pc-mu .sym, .pc-points .sym { width: 1em; height: 1em; }

/* Each type gets its own frame and arrangement. */
/* Events: cut corners, a one-shot. */
.t-event { clip-path: polygon(1.3em 0, 100% 0, 100% calc(100% - 1.3em), calc(100% - 1.3em) 100%, 0 100%, 0 1.3em); }
/* Operations: the Corp's events, cut the other way. */
.t-operation { clip-path: polygon(0 0, calc(100% - 1.3em) 0, 100% 1.3em, 100% 100%, 1.3em 100%, 0 calc(100% - 1.3em)); }
/* Programs: a chip-like art window and a trace under the title. */
.t-program .pc-art { border-radius: .2em; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08), 0 0 0 .2em #0b1116, 0 0 0 .32em var(--edge); margin: .2em; }
.t-program .pc-head { border-bottom: 1px dashed var(--edge); }
/* Hardware: brushed metal plate. */
.t-hardware { background: repeating-linear-gradient(90deg, rgba(255,255,255,.015) 0 2px, transparent 2px 5px), linear-gradient(160deg, #1b232b, #0c1116 70%); border-style: double; border-width: 4px; }
/* Resources: softer, rounded windows. */
.t-resource .pc-art { border-radius: 1.6em 1.6em .35em .35em; }
/* ICE: art first, a hazard stripe, and the subroutines lined up. */
.t-ice { grid-template-rows: minmax(0, 1fr) auto auto auto auto; }
.t-ice .pc-art { order: -1; }
.t-ice::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: .45em; z-index: 1; opacity: .65;
  background: repeating-linear-gradient(-45deg, var(--tone) 0 .5em, transparent .5em 1em); }
.t-ice .pc-text p.sub { border-left: 2px solid color-mix(in oklab, var(--tone) 55%, transparent); padding: .1em 0 .1em .45em; }
/* Agendas: a gold double rule, and the points large. */
.t-agenda { border: 4px double var(--gold); }
.t-agenda .pc-points { font-size: 1.7em; }
/* Assets and upgrades: an arched window over the Corp's business. */
.t-asset .pc-art, .t-upgrade .pc-art { border-radius: 50% 50% .35em .35em / 1.6em 1.6em .35em .35em; }

/* --- server details and the match log --------------------------------------- */
.details { position: relative; min-height: 0; overflow: auto; padding: 14px; display: grid; grid-template-columns: 1fr; gap: 12px; align-content: start; border-bottom: 1px solid #172230; max-height: 64vh; }
.details.empty { color: var(--dim); }
.details.empty h2, .log h2 { margin: 0; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
.details.empty p { margin: 0; font-size: 13.5px; }
.details .keys { color: var(--faint); font-size: 12px; }
.details .close { position: absolute; top: 8px; right: 10px; background: transparent; border: 0; color: var(--dim); font-size: 20px; }
.detailart { width: min(100%, 200px); aspect-ratio: 5/7; border-radius: 12px; background: #1a2230 center/cover; box-shadow: var(--e2); justify-self: center; }
.server-art { display: grid; place-items: center; background: url(/art/meridian-datacenter.svg) center / cover #0b1014; font-weight: 700; letter-spacing: .14em; color: var(--mat-ink); aspect-ratio: 3/2; }
.detailtext h2 { margin: 0; font-size: 19px; }
.detailtext .kind { margin: 2px 0; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; }
.detailtext .stats { margin: 0 0 8px; color: var(--dim); font-size: 13px; }
.detailtext .rules { margin: 0 0 8px; }
.detailtext .teach { margin: 0 0 12px; color: var(--dim); font-style: italic; font-size: 13.5px; }
.detailtext .none { color: var(--faint); font-size: 13px; }
.detailtext .credit { margin-top: 14px; color: var(--faint); font-size: 11.5px; }
.iceentry { margin-bottom: 8px; font-size: 13.5px; }
.iceentry span { color: var(--dim); font-size: 12.5px; }
.iceentry p { margin: 2px 0 0; }
.icelist .sub { color: var(--faint); font-size: 11.5px; text-transform: uppercase; letter-spacing: .1em; }
/* The score areas: each agenda as a row to read. */
.score-side { margin: 14px 0 6px; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--gold); }
.agenda-list { display: grid; gap: 8px; }
.agenda-row { display: grid; grid-template-columns: 44px 1fr; gap: 10px; align-items: start; text-align: left; padding: 6px; border-radius: 10px;
  background: rgba(242,195,90,.05); border: 1px solid rgba(242,195,90,.25); }
.agenda-row:hover { background: rgba(242,195,90,.1); }
.agenda-art { width: 44px; aspect-ratio: 5/7; border-radius: 5px; background: center 28% / cover #1a2230; }
.agenda-text { font-size: 13px; }
.agenda-text .pts { color: var(--gold); font-weight: 700; font-size: 12px; }
.agenda-rules { display: block; margin-top: 2px; color: var(--dim); font-size: 12.5px; }
.log { min-height: 0; overflow: auto; padding: 12px 14px; display: grid; gap: 8px; align-content: start; }
.notes { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 13px; color: var(--dim); }
.notes li { animation: up var(--t-med) var(--ease-out); }
.notes li span { font-weight: 700; margin-right: 6px; font-size: 11.5px; }
.notes li.Meridian span { color: var(--mat-ink); }
.notes li.you span { color: var(--runner); }
.notes li.table { color: var(--fg); }

/* --- Hear: the deck's transcription, as a status readout in the top bar ------ */
.topbar .hear { display: inline-flex; align-items: center; gap: 8px; min-width: 0; max-width: 40vw; padding: 2px 10px; border-radius: 8px; background: rgba(140,120,200,.09); }
.topbar .hear .rec { flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--alert); }
.topbar .hear b { flex: none; color: var(--hear); font-size: 12px; letter-spacing: .04em; }
.topbar .hear .meter { flex: none; display: inline-flex; align-items: flex-end; gap: 2px; height: 12px; width: 32px; }
.topbar .hear .meter i { flex: 1; background: var(--hear); border-radius: 1px; transition: height .09s; }
.caption { min-width: 0; color: var(--dim); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.caption.fresh { animation: capfade 6s forwards; }
@keyframes capfade { 0%, 66% { opacity: 1; } 100% { opacity: .15; } }
.caption .src { color: var(--faint); font: 11px var(--mono); }

/* --- match over ----------------------------------------------------------------- */
.result { position: fixed; inset: 0; display: grid; place-items: center; background: rgba(3,6,10,.7); backdrop-filter: blur(3px); z-index: 20; padding: 16px; }
.result > div { background: var(--panel-2); border: 1px solid var(--line); border-radius: 16px; padding: 28px; text-align: center; display: grid; gap: 12px; max-width: 420px;
  box-shadow: var(--e3); animation: up .3s var(--ease-out); }
.result h2 { margin: 0; font-size: 28px; }
.result p { margin: 0; color: var(--dim); }

/* --- phones and narrow windows: the deck's portrait layout ------------------ */
@media (max-width: 820px), (max-height: 500px) and (orientation: landscape) {
  :root { --card-w: calc(clamp(46px, min(15vw, 8.6vh), 84px) * var(--fit, 1)); }
  .side { display: contents; transform: none; }
  .log { display: none; }
  .details.empty { display: none; }
  .details:not(.empty) { position: fixed; left: 0; right: 0; bottom: 0; max-height: 82vh; z-index: 15; background: var(--panel-2); border-top: 1px solid var(--line);
    border-radius: 18px 18px 0 0; grid-template-columns: 110px 1fr; box-shadow: var(--e3); animation: up var(--t-med) var(--ease-out); padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
  .details:not(.empty) .detailart { width: 110px; }
  .details.score { grid-template-columns: 1fr; }
  .strip { gap: 10px; font-size: 13px; }
  .where { display: none; }
  .topbar { gap: 6px 8px; flex-wrap: wrap; }
  .topbar .ghost { white-space: nowrap; padding: 4px 6px; font-size: 12px; }
  /* Hear drops to its own full-width row so its captions still fit. */
  .topbar .hear { order: 10; flex-basis: 100%; max-width: none; }
  .brand { font-size: 11px; letter-spacing: .1em; }
  /* The whole table scrolls on a phone, so Meridian's side keeps its natural height. */
  .board { grid-template-rows: auto auto; }
  .corp-mat { grid-template-rows: auto auto; }
  /* The racks scroll sideways, each with its gateway. Chassis keep only their
     cards, and the network band's scenery stays off a screen this small. */
  .servers { padding: 8px 6px 6px; }
  .racks { gap: 4px; grid-auto-columns: calc(var(--card-h) + 12px); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; }
  .rack { padding: 4px 3px; }
  .rack::before, .rack::after { width: 2px; left: 1px; }
  .rack::after { left: auto; right: 1px; }
  .plate { min-height: 18px; padding: 0 3px 0 5px; }
  .plate b { font-size: 9px; letter-spacing: .06em; }
  .plate .readout { font-size: 8.5px; padding: 0 4px; letter-spacing: .06em; }
  .plate .readout i { margin-right: 3px; }
  .chassis { padding: 3px; gap: 0; justify-content: center; }
  .chassis::before, .chassis::after, .detail, .leds { display: none; }
  .serverch { min-height: calc(var(--card-h) + 6px); }
  .icech { min-height: calc(var(--card-w) + 6px); }
  .gate { width: 26px; height: 26px; }
  .gate .hex { width: 22px; height: 22px; }
  .gate .hex::before { width: 18px; height: 18px; }
  .gwlbl, .netband { display: none; }
  .runner-mat { margin: 0; border-radius: 14px 14px 0 0; }
  .strip.runner { border-radius: 14px 14px 0 0; padding-left: 12px; }
  .runner-mat .crack { width: 150px; height: 96px; background-size: contain; }
  .vents, .usbc { display: none; }
  .deck-face { grid-template-columns: minmax(0, 1fr); grid-template-areas: "screen" "rig" "grip" "keys"; gap: 6px; padding: 6px 8px 8px; }
  .latch-screen { max-height: 26vh; padding: 6px 8px 8px; }
  .screen-body p { font-size: 13.5px; line-height: 1.4; }
  /* The module and the piles share the rig row; the bays wrap as the rig fills (see the grip drawer below). */
  .rowlabel { display: none; }
  .rigbay { padding: 3px 8px 3px 10px; }
  .module { gap: 14px; padding: 5px 40px 3px 14px; }
  .module .micro { display: none; }
  .silk { font-size: 7.5px; letter-spacing: .12em; }
  .slots { gap: 8px; }
  .deck-side { gap: 6px; padding-left: 8px; }
  .pile { font-size: 11px; }
  /* The key bed stacks: three lines of the session log over full-width keys. */
  /* No session log on a phone: the screen is small, so the keys get the whole
     key bed and the cards keep their room. The log lives on wider screens. */
  .keybed { height: auto; padding: 6px 8px; }
  /* No session log on a phone: the key bed is just the buttons, full width. */
  .slog { display: none; }
  .keyset { flex-direction: column; align-items: stretch; gap: 0; font-size: 14px; }
  .keyset::before { display: none; }
  .keycap { max-width: none; margin: 0; padding: 9px 6px; }
  .callout { font-size: 11.5px; white-space: normal; max-width: 70vw; text-align: center; }
  .callout.corner { display: none; }
  .review { left: 8px !important; right: 8px; width: auto; grid-template-columns: 1fr; justify-items: center; gap: 8px; }
  .review-side { width: 100%; padding: 10px 12px; }
  /* A phone keeps to the cards in play: no rack equipment, no M.2 module,
     no casing details. ICE still lies on its side, and the gateways that
     start runs stay under each server. */
  .rack, .rack.target, .server.selected .rack { padding: 0; box-shadow: none; }
  .rackbg, .beacon, .edges { display: none; }
  .plate { min-height: 16px; padding: 0 2px; justify-content: center; gap: 5px; background: none; border: 0; }
  .server.selected .plate b { color: var(--mat-ink); }
  .plate .readout { padding: 0; background: none; box-shadow: none; }
  .chassis { padding: 0; background: none; box-shadow: none; }
  .icestack { gap: 6px; }
  .socket, .pcb, .module .notch, .standoff { display: none; }
  .rigbay, .module { padding: 0; border-radius: 0; background: none; box-shadow: none; }
  /* Room for the cost coins that hang off each card's corner. */
  .rigbay { padding: 9px 6px 2px 10px; scrollbar-width: thin; }
  .module { gap: 12px; }
  .mbay-label { padding: 0; }
  /* No socket chrome on a phone: just the cards. */
  .sock::before, .sock::after { display: none; }
  .bay-empty .sock.empty { display: none; }
}

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

/* --- KITE Access (W2 S1). A remote access portal: sign in, pick a workspace,
   connect. Then the session viewer: a slim toolbar with a tab per identity in
   its accent, the remote desktop below, Hear and the open windows along the
   bottom. The portal is quiet and businesslike; the desktops behind it are
   Catalyst's own, lived in and dim. --------------------------------------- */
.access { min-height: 100%; display: flex; align-items: center; justify-content: center; padding: 24px 16px;
  background: radial-gradient(110% 70% at 50% 0%, #0f1a26 0%, var(--bg) 72%); }
.access-panel { width: min(420px, 100%); background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-panel);
  box-shadow: var(--e2); padding: 26px; }
.access-panel.wide { width: min(760px, 100%); }
.access-panel h1 { margin: 6px 0 14px; font: 600 20px/1.25 var(--ui); }
.access-form { display: flex; flex-direction: column; gap: 14px; }
.access-form h1 { margin: 0; }
.access-form label { display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--dim); }
.access-form input { font: inherit; font-size: 15px; color: var(--fg); background: var(--bg); border: 1px solid var(--line); border-radius: 8px; padding: 9px 10px; }
.access-form input:focus-visible { outline: 2px solid #93b4ff; outline-offset: 1px; }
.access .dim, .viewer .dim { color: var(--dim); font-size: 13px; margin: 0; }
.access .fine { color: var(--faint); font-size: 12px; margin: 14px 0 0; }
.outside { font: 11px var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--gold); }
.access-brand { display: flex; align-items: center; gap: 8px; font: 700 13px var(--mono); letter-spacing: .16em; color: #93b4ff; }
.kite-mark { flex: none; }
.access-rows { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; margin: 0; font-size: 14px; }
.access-rows dt { font: 12px var(--mono); color: var(--faint); align-self: center; }
.access-rows dd { margin: 0; }
.portal-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
.portal-head .dim { flex: 1; font: 12px var(--mono); }
.seats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.seat { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 14px; padding: 12px 14px;
  background: var(--panel-2); border: 1px solid var(--line); border-left: 3px solid var(--accent); border-radius: 10px; }
.seat-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--faint); }
.seat-dot.on { background: #7fd6a3; box-shadow: 0 0 6px #7fd6a3; }
.seat-dot.held { background: var(--gold); }
.seat-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.seat-main b { font-size: 15px; }
.seat-who { color: var(--accent); font-size: 13px; }
.seat-purpose { color: var(--dim); font-size: 13px; }
.seat-meta { font: 12px var(--mono); color: var(--faint); }
.seat-connect { border-color: var(--line); color: var(--fg); padding: 6px 14px; }
.banner-screen { cursor: pointer; background: #05080c; }
.banner-text { width: min(760px, 100%); font: 14px/1.6 var(--mono); color: var(--dim); }
.banner-text p { margin: 0; white-space: pre-wrap; }
.banner-text p.first { color: var(--fg); margin-bottom: 4px; }
.banner-go { margin-top: 26px; color: var(--faint); padding-left: 0; }
.banner-go.ready { color: #93b4ff; animation: kite-pulse 2.4s ease-in-out infinite; }

/* The session viewer. */
.viewer { height: 100%; display: grid; grid-template-rows: auto 1fr auto; background: var(--bg); overflow: hidden; }
.viewer-bar { display: flex; align-items: center; gap: 10px; padding: 0 10px; height: 38px; background: #090d13;
  border-bottom: 1px solid color-mix(in oklab, var(--accent) 35%, var(--line)); font-size: 13px; min-width: 0; }
.kite-button { display: flex; align-items: center; gap: 6px; background: none; border: 1px solid transparent; border-radius: 6px;
  padding: 4px 8px; color: #93b4ff; font: 700 12px var(--mono); letter-spacing: .14em; }
.kite-button:hover, .kite-button[aria-expanded="true"] { border-color: var(--line); background: var(--panel); }
.sessions { display: flex; gap: 2px; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.session { display: flex; align-items: center; gap: 6px; white-space: nowrap; background: none; border: 0; border-radius: 6px;
  padding: 4px 10px; color: var(--dim); }
.session .n { font: 11px var(--mono); color: var(--faint); border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; }
.session .who { color: var(--faint); }
.session:hover { color: var(--fg); background: var(--panel); }
.session.current { color: var(--fg); background: color-mix(in oklab, var(--accent) 14%, transparent); }
.session.current .n { color: #071015; background: var(--accent); border-color: var(--accent); }
.session.current .who { color: var(--accent); }
.viewer-bar .spacer { flex: 1; }
.viewer-bar .short { display: none; }
@media (max-width: 720px) { .viewer-bar .short { display: inline; } }
.readouts { display: flex; gap: 14px; font: 12px var(--mono); color: var(--dim); white-space: nowrap; }
.readouts .clock { color: var(--fg); }
.bars { display: inline-flex; align-items: flex-end; gap: 1px; height: 10px; }
.bars i { width: 3px; background: var(--dim); }
.bars i:nth-child(1) { height: 3px; } .bars i:nth-child(2) { height: 5px; } .bars i:nth-child(3) { height: 7px; } .bars i:nth-child(4) { height: 10px; }
.battery { display: inline-flex; gap: 1px; } .battery i { width: 3px; height: 9px; background: var(--line); } .battery i.on { background: var(--dim); }

.desk-area { position: relative; overflow: hidden;
  background: radial-gradient(90% 70% at 70% 100%, color-mix(in oklab, var(--accent) 9%, transparent) 0%, transparent 70%),
    repeating-linear-gradient(0deg, rgba(255,255,255,.012) 0 1px, transparent 1px 28px), #0a0f15; }
.watermark { position: absolute; left: 14px; bottom: 10px; font: 11px var(--mono); color: color-mix(in oklab, var(--accent) 40%, var(--faint)); opacity: .55; }
.desk-empty { position: absolute; inset: 0; display: grid; place-items: center; color: var(--faint); margin: 0; font-size: 13px; }

.win { position: absolute; display: flex; flex-direction: column; min-width: 0; background: var(--panel); border: 1px solid var(--line);
  border-radius: 10px; box-shadow: var(--e1); overflow: hidden; }
.win.focused { border-color: color-mix(in oklab, var(--accent) 45%, var(--line)); box-shadow: var(--e2); }
.win.min { display: none; }
.win.max { inset: 0; border-radius: 0; }
.win-bar { display: flex; align-items: center; gap: 8px; padding: 6px 6px 6px 12px; border-bottom: 1px solid var(--line);
  background: color-mix(in oklab, var(--panel-2) 80%, #000); cursor: grab; user-select: none; touch-action: none; }
.win.max .win-bar { cursor: default; }
.win-bar h2 { flex: 1; margin: 0; font: 600 13px/1.2 var(--ui); color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.win.focused .win-bar h2 { color: var(--fg); }
.win-keys { display: flex; gap: 2px; }
.win-keys button { width: 26px; height: 22px; display: grid; place-items: center; background: none; border: 1px solid transparent;
  border-radius: 5px; color: var(--faint); font-size: 13px; line-height: 1; }
.win-keys button:hover { color: var(--fg); border-color: var(--line); }
.win-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.win-size { position: absolute; right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; touch-action: none;
  background: linear-gradient(135deg, transparent 50%, var(--line) 50% 60%, transparent 60% 70%, var(--line) 70% 80%, transparent 80%); }

.talk { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.transcript { flex: 1; list-style: none; margin: 0; padding: 10px 14px 6px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.line { display: grid; grid-template-columns: auto auto 1fr; gap: 0 8px; align-items: baseline; }
.line .at { font: 12px var(--mono); color: var(--faint); }
.line b { font-weight: 700; font-size: 13px; }
.line > span:last-child { grid-column: 3; }
.line.agent b { color: var(--latch); }
.line.person b { color: var(--gold); }
.line.you b { color: var(--dim); }
.line.you > span:last-child { color: color-mix(in oklab, var(--fg) 82%, var(--dim)); }
.line.system { grid-template-columns: auto 1fr; font: 13px/1.4 var(--mono); color: var(--dim); }
.line.system > span:last-child { grid-column: 2; }
.line.note { display: block; font-size: 13px; color: var(--faint); font-style: italic; }
.line.empty { display: block; color: var(--faint); font-size: 13px; }
.app-hear .line.system { color: var(--hear); }
.composing { color: var(--faint); font-size: 13px; font-style: italic; animation: kite-pulse 1.4s ease-in-out infinite; }
.transcript .end { height: 1px; flex: none; }
@keyframes kite-pulse { 50% { opacity: .45; } }
.replies { display: flex; flex-direction: column; gap: 6px; padding: 10px 14px 14px; border-top: 1px solid var(--line); }
.reply { display: flex; gap: 10px; align-items: baseline; text-align: left; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 8px; padding: 8px 12px; }
.reply:hover:not(:disabled), .reply:focus-visible { border-color: color-mix(in oklab, var(--latch) 55%, var(--line)); }
.reply .mark { font: 11px var(--mono); color: var(--faint); text-transform: uppercase; letter-spacing: .08em; min-width: 2.2em; }
.reply.do > span:last-child { color: var(--dim); }
.kite-table { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 10px 14px 14px;
  border-top: 1px solid var(--line); color: var(--dim); font-size: 13px; }

.work-idle { flex: 1; padding: 18px 20px; display: flex; flex-direction: column; gap: 8px; }
.work-idle p { margin: 0; }
.work-idle .work-head { font: 600 12px var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--accent); }
.work-idle.meridian { font-family: var(--mono); font-size: 13px; }

.viewer-foot { display: flex; align-items: center; gap: 10px; height: 34px; padding: 0 10px; border-top: 1px solid var(--line); background: #090d13; min-width: 0; }
.hear-strip { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 0 1 46%; background: none; border: 1px solid transparent;
  border-radius: 6px; padding: 3px 8px; text-align: left; }
.hear-strip:hover { border-color: var(--line); }
.hear-strip b { color: var(--hear); font-size: 12px; }
.hear-strip .rec { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); flex: none; }
.hear-strip .rec.live { background: var(--alert); box-shadow: 0 0 6px var(--alert); }
.hear-strip .caption { font: 12px var(--mono); color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.taskbar { flex: 1; display: flex; justify-content: flex-end; gap: 4px; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.task { white-space: nowrap; background: none; border: 1px solid var(--line); border-radius: 6px; padding: 3px 10px; color: var(--dim); font-size: 12px; }
.task.front { color: var(--fg); border-color: color-mix(in oklab, var(--accent) 50%, var(--line)); }
.task.min { opacity: .6; }

.notices { position: fixed; right: 14px; top: 50px; display: flex; flex-direction: column; gap: 8px; width: min(330px, calc(100vw - 28px)); z-index: 50;
  max-height: calc(100vh - 50px - 96px); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; padding-bottom: 2px; }
.notices > .notice { flex: none; }
.notice { background: var(--panel-2); border: 1px solid var(--line); border-left: 3px solid #93b4ff; border-radius: 10px; padding: 10px 12px; box-shadow: var(--e2);
  display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; animation: kite-in var(--t-med) var(--ease-out); }
.notice.ad { border-left-color: var(--faint); }
.notice b { font-size: 13px; }
.notice .tag { font: 11px var(--mono); color: var(--faint); align-self: center; }
.notice p { grid-column: 1 / -1; margin: 0; font-size: 13px; color: var(--dim); }
.notice button { grid-column: 2; justify-self: end; }
@keyframes kite-in { from { opacity: 0; transform: translateY(-6px); } }

.menu-scrim { position: fixed; inset: 38px 0 0; z-index: 60; background: rgba(3, 6, 10, .45); }
.kite-menu { position: absolute; left: 8px; top: 6px; width: min(560px, calc(100vw - 16px)); max-height: calc(100% - 20px); overflow: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-panel); box-shadow: var(--e3); padding: 10px 12px 14px; }
.menu-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 8px; }
.menu-tabs button { background: none; border: 0; border-bottom: 2px solid transparent; padding: 6px 12px; color: var(--dim); }
.menu-tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: #93b4ff; }
.menu-apps h3 { margin: 12px 4px 4px; font: 600 11px var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.menu-item { display: flex; align-items: baseline; gap: 10px; width: 100%; text-align: left; background: none; border: 1px solid transparent;
  border-radius: 8px; padding: 7px 10px; }
.menu-item:hover, .menu-item:focus-visible { background: var(--panel-2); border-color: var(--line); }
.menu-item b { font-weight: 600; font-size: 14px; }
.menu-item span:last-child { margin-left: auto; color: var(--faint); font-size: 12px; }
.menu-item .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); align-self: center; }
.menu-procs table { width: 100%; border-collapse: collapse; font: 12px var(--mono); }
.menu-procs th { text-align: left; color: var(--faint); font-weight: 400; padding: 4px 6px; border-bottom: 1px solid var(--line); }
.menu-procs td { padding: 5px 6px; border-bottom: 1px solid color-mix(in oklab, var(--line) 50%, transparent); color: var(--dim); }
.menu-procs td:first-child { color: var(--fg); }
.menu-procs .figure { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.menu-procs .ws { color: var(--accent); }
.menu-procs p { margin-top: 10px; }

/* A phone shows one window at a time, the one in front, full size. */
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .viewer-bar { gap: 6px; padding: 0 6px; }
  .kite-button span, .session .who, .readouts span:not(.clock), .viewer-bar .long { display: none; }
  .session { padding: 4px 7px; font-size: 0; gap: 0; }
  .sessions { flex: none; overflow: visible; }
  .readouts { min-width: 0; overflow: hidden; }
  .readouts .night { display: none; }
  .portal-head .dim { order: 3; flex-basis: 100%; }
  .session .n { font-size: 12px; }
  .readouts { font-size: 11px; }
  .viewer-bar .ghost.small { padding: 4px 6px; font-size: 12px; }
  .win { position: absolute !important; inset: 0 !important; width: auto !important; height: auto !important; border-radius: 0; display: none; }
  .win.focused { display: flex; }
  .win-size, .win-keys button[aria-label="Maximize"], .win-keys button[aria-label="Restore"] { display: none; }
  .win-bar { cursor: default; }
  .viewer-foot { height: auto; flex-wrap: wrap; padding: 4px 6px; }
  .hear-strip { flex-basis: 100%; }
  .taskbar { justify-content: flex-start; }
  .seat { grid-template-columns: auto 1fr; }
  .seat button { grid-column: 1 / -1; }
  .menu-procs { overflow-x: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .composing, .notice, .banner-go.ready { animation: none; }
}

/* KITE Access: the player's real sign-in, set apart from the fiction above it. */
.returning { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding-top: 12px; border-top: 1px solid var(--line); }
.real-keys { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; padding: 12px 14px;
  border: 1px dashed color-mix(in oklab, var(--gold) 45%, var(--line)); border-radius: 10px; }
.real-keys p { margin: 0; }
.real-keys > button { align-self: flex-start; }
.key-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Spool Messenger (W2 S2): conversations down the side, the thread beside. */
.spool { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(120px, 34%) 1fr; }
.spool-contacts { display: flex; flex-direction: column; border-right: 1px solid var(--line); overflow-y: auto; }
.spool-contact { display: grid; grid-template-columns: 1fr auto; gap: 2px 6px; text-align: left; background: none; border: 0;
  border-bottom: 1px solid color-mix(in oklab, var(--line) 60%, transparent); padding: 10px 12px; }
.spool-contact:hover, .spool-contact.current { background: var(--panel-2); }
.spool-contact b { font-size: 14px; }
.spool-contact .preview { grid-column: 1 / -1; color: var(--faint); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.badge { min-width: 18px; padding: 0 5px; border-radius: 9px; background: #9fd3ff; color: #071015; font: 700 11px/18px var(--mono); text-align: center; }
.spool-thread { min-height: 0; display: flex; flex-direction: column; }
.spool-empty { margin: auto; color: var(--faint); font-size: 13px; }
.app-spool .line.person b { color: #9fd3ff; }
.notice.message { border-left-color: #9fd3ff; }
.notice-keys { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 4px; }
.hear-strip .meter { display: inline-flex; align-items: center; gap: 2px; height: 12px; }
.hear-strip .meter i { width: 2px; height: 2px; background: var(--hear); opacity: .5; }
.hear-strip .meter.live i { animation: hear-level .5s ease-in-out infinite alternate; opacity: .9; }
.hear-strip .meter.live i:nth-child(2) { animation-delay: .12s; } .hear-strip .meter.live i:nth-child(3) { animation-delay: .24s; }
.hear-strip .meter.live i:nth-child(4) { animation-delay: .06s; } .hear-strip .meter.live i:nth-child(5) { animation-delay: .18s; }
@keyframes hear-level { from { height: 2px; } to { height: 11px; } }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) { .spool { grid-template-columns: 1fr; grid-template-rows: auto 1fr; } .spool-contacts { flex-direction: row; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); } .spool-contact .preview { display: none; } }
@media (prefers-reduced-motion: reduce) { .hear-strip .meter.live i { animation: none; height: 8px; } }

.hear-strip .now-playing { margin-left: auto; padding-left: 10px; font: 11px var(--mono); color: var(--faint); white-space: nowrap; }

/* --- The KITE desktop: a well-used GNOME-style session. A top bar with the
   launcher and Hear on the left, the clock centered, status and the account
   menu on the right; the account's desktop; a dock of its apps. Work
   profiles wear a briefcase and a plainer, managed wallpaper. -------------- */
.topbar-kite { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 10px; height: 34px; padding: 0 8px;
  background: #07090d; border-bottom: 1px solid color-mix(in oklab, var(--accent) 30%, #11161d); font-size: 13px; min-width: 0; z-index: 5; }
.tb-left, .tb-right { display: flex; align-items: center; gap: 8px; min-width: 0; }
.tb-left { flex: 1 1 0; }
.tb-right { flex: 1 1 0; justify-content: flex-end; }
.tb-clock { flex: none; font: 13px var(--mono); color: var(--dim); white-space: nowrap; }
.tb-clock b { color: var(--fg); font-weight: 600; }
.tb-status { display: flex; align-items: center; gap: 6px; font: 12px var(--mono); color: var(--dim); white-space: nowrap; }
.topbar-kite .hear-strip { flex: 0 1 auto; min-width: 0; max-width: 46ch; }
.account-chip { display: flex; align-items: center; gap: 7px; background: none; border: 1px solid transparent; border-radius: 16px; padding: 2px 10px 2px 3px; color: var(--fg); }
.account-chip:hover, .account-chip[aria-expanded="true"] { background: var(--panel); border-color: var(--line); }
.account-chip .who { font-size: 13px; max-width: 16ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.account-avatar { position: relative; flex: none; display: inline-grid; place-items: center; width: var(--size); height: var(--size); border-radius: 50%;
  background: color-mix(in oklab, var(--accent) 22%, #0c1118); color: var(--accent); border: 1px solid color-mix(in oklab, var(--accent) 45%, transparent); }
.account-avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.account-avatar .monogram { font: 600 calc(var(--size) * .38) var(--ui); letter-spacing: .02em; color: color-mix(in oklab, var(--accent) 80%, white); }
.account-avatar .badge-case { position: absolute; right: -4px; bottom: -3px; display: grid; place-items: center; padding: 1px; border-radius: 5px;
  background: #0b0f15; color: var(--accent); border: 1px solid color-mix(in oklab, var(--accent) 55%, transparent); }

.viewer .desk-area { background: radial-gradient(80% 60% at 70% 90%, color-mix(in oklab, var(--accent) 7%, transparent), transparent 70%), #0a0e13; }
.wallpaper { position: absolute; inset: 0; pointer-events: none; }
/* Home: groundside, the coast Catalyst keeps applying to live on
   (assets/groundside), shaded at the top and bottom so the bar, the desktop's
   files and the dock stay readable. */
.wallpaper.home { background: linear-gradient(180deg, rgba(5, 8, 14, .38), rgba(5, 8, 14, .06) 30%, rgba(5, 8, 14, .08) 65%, rgba(5, 8, 14, .5)),
  url(/art/groundside-coast-v1.webp) 62% center / cover no-repeat, #1b2a44; }
.desk-files { list-style: none; margin: 0; padding: 14px; display: flex; flex-direction: column; gap: 14px; width: 120px; }
.desk-files li { display: flex; flex-direction: column; align-items: center; gap: 4px; font-size: 11px; color: var(--dim); text-align: center; text-shadow: 0 1px 2px #000; }
.wallpaper .host { position: absolute; right: 14px; bottom: 8px; font: 11px var(--mono); color: var(--faint); opacity: .5; }
.wallpaper.work { display: grid; place-items: center; background: linear-gradient(180deg, color-mix(in oklab, var(--accent) 4%, #0b0f14), #090c10); }
.wallpaper.work .case { color: color-mix(in oklab, var(--accent) 22%, transparent); }
.wallpaper.work .managed { position: absolute; left: 0; right: 0; bottom: 10px; text-align: center; font: 11px var(--mono); color: color-mix(in oklab, var(--accent) 50%, var(--faint)); opacity: .7; }
.win-work { color: var(--accent); display: grid; place-items: center; }
.unlocked { position: absolute; left: 50%; top: 12px; transform: translateX(-50%); z-index: 40; display: flex; align-items: center; gap: 8px;
  padding: 6px 14px; border-radius: 16px; background: color-mix(in oklab, var(--accent) 16%, #0b0f15); border: 1px solid color-mix(in oklab, var(--accent) 45%, transparent);
  color: var(--fg); font-size: 13px; box-shadow: var(--e2); animation: kite-in var(--t-med) var(--ease-out); }
.unlocked svg { color: var(--accent); }
.unlocked span { color: var(--dim); }

.dock { display: flex; justify-content: center; gap: 4px; padding: 5px 10px 7px; background: #07090d; border-top: 1px solid #11161d; overflow-x: auto; scrollbar-width: none; }
.dock-app { position: relative; display: grid; place-items: center; width: 44px; height: 40px; background: none; border: 1px solid transparent; border-radius: 10px; color: var(--dim); }
.dock-app:hover, .dock-app:focus-visible { background: var(--panel); border-color: var(--line); color: var(--fg); }
.dock-app.running::after { content: ""; position: absolute; bottom: 1px; width: 4px; height: 4px; border-radius: 50%; background: var(--dim); }
.dock-app.front::after { background: var(--accent); width: 12px; border-radius: 2px; }
.dock-app.work { color: var(--accent); }
.dock-app .badge { position: absolute; top: 0; right: 2px; }
.app-glyph { display: grid; place-items: center; color: inherit; }
.app-glyph.glyph-hear { color: var(--hear); }
.app-glyph.glyph-board { color: var(--gold); }
.viewer .short { display: none; }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) { .viewer .short { display: inline; } .viewer .long { display: none; } }

.tabbed { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.tabs { display: flex; gap: 2px; padding: 0 10px; border-bottom: 1px solid var(--line); }
.tabs button { display: flex; align-items: center; gap: 6px; background: none; border: 0; border-bottom: 2px solid transparent; padding: 7px 10px; color: var(--dim); font-size: 13px; }
.tabs button[aria-selected="true"] { color: var(--fg); border-bottom-color: var(--accent); }
.harness-settings { padding: 14px 18px; overflow-y: auto; }
.harness-settings dl { display: grid; grid-template-columns: auto 1fr; gap: 8px 18px; margin: 0 0 14px; font-size: 13px; }
.harness-settings dt { color: var(--faint); font: 12px var(--mono); }
.harness-settings dd { margin: 0; }
.harness-settings .off { color: var(--gold); font-weight: 600; }

.letter { min-height: 0; overflow-y: auto; padding: 14px 18px; font-size: 14px; line-height: 1.55; }
.letter h3 { margin: 0 0 2px; font-size: 16px; }
.letter header { margin-bottom: 12px; }
.letter p { margin: 0 0 10px; }
.spool-contact.unread b::after { content: " ●"; color: #9fd3ff; font-size: 10px; vertical-align: middle; }
.notice.mail { border-left-color: #9fd3ff; }

.files { flex: 1; min-height: 0; display: grid; grid-template-columns: 150px 1fr; }
.files-places { display: flex; flex-direction: column; gap: 4px; padding: 10px; border-right: 1px solid var(--line); font-size: 13px; color: var(--dim); }
.files-places b { margin-top: 8px; font: 600 11px var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--faint); }
.files-places .current { color: var(--fg); }
.files-main { padding: 10px 14px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.file-list { list-style: none; margin: 0; padding: 0; }
.file-list button { display: flex; justify-content: space-between; gap: 10px; width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid color-mix(in oklab, var(--line) 50%, transparent); padding: 7px 4px; font-size: 13px; }
.file-list button:hover { background: var(--panel-2); }
.devices p { margin: 0 0 6px; font-size: 13px; }

.settings { padding: 12px 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 16px; }
.settings h3 { margin: 0 0 8px; font: 600 11px var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.settings-account { display: flex; gap: 12px; align-items: flex-start; padding: 8px 0; border-bottom: 1px solid color-mix(in oklab, var(--line) 50%, transparent); }
.settings-who { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.settings-who .dim { display: flex; align-items: center; gap: 5px; }
.avatar-choices { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.avatar-choices button { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%; background: var(--panel-2); border: 1px solid var(--line); color: var(--accent); }
.avatar-choices button[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 30%, transparent); }
.avatar-choices .upload { display: inline-flex; align-items: center; padding: 0 10px; border-radius: 16px; border: 1px dashed var(--line); color: var(--dim); font-size: 12px; cursor: pointer; }
.avatar-choices .upload input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.avatar-choices .upload:focus-within { outline: 2px solid var(--accent); }

.app-grid { width: min(620px, calc(100vw - 16px)); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 8px; }
.grid-app { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 12px 8px; background: none; border: 1px solid transparent; border-radius: 12px; color: var(--fg); text-align: center; }
.grid-app:hover, .grid-app:focus-visible { background: var(--panel-2); border-color: var(--line); }
.grid-app b { font-size: 13px; font-weight: 600; }
.grid-app span:last-child { font-size: 11px; color: var(--faint); }
.account-menu { left: auto; right: 8px; width: min(360px, calc(100vw - 16px)); }
.account-menu h3 { margin: 4px 6px 8px; font: 600 11px var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.account-row { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; background: none; border: 1px solid transparent; border-radius: 10px; padding: 8px; color: var(--fg); }
.account-row:hover, .account-row:focus-visible { background: var(--panel-2); border-color: var(--line); }
.account-row.current { background: color-mix(in oklab, var(--accent) 10%, transparent); border-color: color-mix(in oklab, var(--accent) 35%, transparent); }
.account-who { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.account-who b { font-size: 14px; }
.account-who span { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--faint); }
.account-row .key { font: 11px var(--mono); color: var(--faint); }
.account-actions { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
.viewer .menu-scrim { inset: 34px 0 0; }
.viewer .notices { top: 44px; }

@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .topbar-kite { padding: 0 4px; gap: 6px; }
  .topbar-kite .hear-strip .caption, .topbar-kite .now-playing, .tb-status .relay, .tb-status .pct, .account-chip .who, .tb-clock .night { display: none; }
  .dock { justify-content: flex-start; }
  .files { grid-template-columns: 1fr; }
  .files-places { flex-direction: row; flex-wrap: wrap; border-right: 0; border-bottom: 1px solid var(--line); }
  .desk-files { display: none; }
}
@media (prefers-reduced-motion: reduce) { .unlocked { animation: none; } }

/* A Meridian employee ID around the player's own avatar on their Meridian
   work profile: a portrait card, a clip slot in Meridian's green band, the
   photo, and at larger sizes MERIDIAN and a barcode. */
.id-badge { position: relative; flex: none; display: inline-flex; flex-direction: column; align-items: stretch;
  width: calc(var(--size) * .82); height: calc(var(--size) * 1.08); border-radius: calc(var(--size) * .1); overflow: visible;
  background: #e9ecef; border: 1px solid color-mix(in oklab, var(--accent) 60%, #000); box-shadow: 0 1px 2px rgba(0,0,0,.5); }
.id-band { display: flex; align-items: center; justify-content: center; gap: 2px; height: 26%; background: var(--accent);
  border-radius: calc(var(--size) * .09) calc(var(--size) * .09) 0 0; }
.id-band .slot { width: 32%; height: 22%; border-radius: 4px; background: #0b0f15; opacity: .75; }
.id-badge.roomy .id-band { flex-direction: column; gap: 1px; }
.id-band b { font: 700 calc(var(--size) * .1) var(--mono); letter-spacing: .08em; color: #06120c; line-height: 1; }
.id-photo { flex: 1; display: grid; place-items: center; margin: 7% 12% 4%; background: #1a2430; color: var(--accent); overflow: hidden; border-radius: 2px; }
.id-photo img { width: 100%; height: 100%; object-fit: cover; }
.id-code { height: 9%; margin: 0 14% 8%; background: repeating-linear-gradient(90deg, #222 0 1px, transparent 1px 2px, #222 2px 4px, transparent 4px 5px); opacity: .7; }
.id-badge .badge-case { position: absolute; right: -5px; bottom: -3px; display: grid; place-items: center; padding: 1px; border-radius: 5px;
  background: #0b0f15; color: var(--accent); border: 1px solid color-mix(in oklab, var(--accent) 55%, transparent); }

.notice.work { border-left-color: var(--accent); }
.notice.work b svg { color: var(--accent); vertical-align: -1px; }

/* The Board inside KITE: the table fills its window (Board fits its cards to
   the space it has), and KITE's top bar already carries the brand and Hear. */
.win-body > .app.embedded, .win-body > .splash { flex: 1; min-height: 0; height: auto; }
.app.embedded .topbar .brand, .app.embedded .topbar .hear { display: none; }
.notices[hidden] { display: none; }

/* The idle screensaver: Latch and Spool riffing on the deck's sensors. */
.saver { position: fixed; inset: 0; z-index: 100; background: rgba(3, 5, 9, .82); cursor: default; }
/* The panel drifts across the free space (saver.ts drift): its corner moves
   between the screen's margins and the panel shifts back by the same
   fraction of its own size, so it always stays on screen. */
.saver-panel { position: absolute; width: min(720px, calc(100% - 32px));
  left: calc(16px + (100% - 32px) * var(--x, .5)); top: calc(16px + env(safe-area-inset-top, 0px) + (100% - 32px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) * var(--y, .5));
  transform: translate(calc(-100% * var(--x, .5)), calc(-100% * var(--y, .5)));
  transition: left 3.2s ease-in-out, top 3.2s ease-in-out, transform 3.2s ease-in-out; background: #0a0e16; border: 1px solid var(--line); border-radius: var(--r-panel); padding: 16px 20px; box-shadow: var(--e3); }
.saver-panel header { display: flex; justify-content: space-between; font: 12px var(--mono); color: var(--faint); }
.saver-riff { min-height: 3em; margin: 14px 0 6px; font-size: 15px; }
.saver-riff b { margin-right: 8px; }
.saver-riff b.latch { color: var(--latch); }
.saver-riff b.spool { color: #a8c8ff; }
.saver-stage { position: relative; height: 96px; margin: 8px 0 14px; border-bottom: 1px solid #1f2a3a; }
.saver-prop { position: absolute; top: 0; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 2px;
  font: 11px var(--mono); color: var(--dim); white-space: nowrap; }
.saver-prop i { font-style: normal; color: var(--faint); }
.saver-actor { position: absolute; bottom: 4px; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 3px;
  transition: left 1.6s var(--ease-out); opacity: .55; }
.saver-actor.talking { opacity: 1; }
.saver-actor i { font: 10px var(--mono); font-style: normal; color: var(--faint); }
.saver-status { list-style: none; margin: 0 0 10px; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; font: 12px var(--mono); color: var(--dim); }
.saver-status li { display: flex; align-items: center; gap: 6px; }
.saver-status .ok, .saver-status .dim-dot { width: 6px; height: 6px; border-radius: 50%; background: #7fd6a3; }
.saver-status .dim-dot { background: var(--gold); }
.saver-hint { margin: 0; font-size: 12px; color: var(--faint); font-style: italic; }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) { .saver-status { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) { .saver-actor, .saver-panel { transition: none; } }

/* The Board's menu as a blade off KITE's top bar, so the table keeps its
   space; on a phone the window's own title bar goes too. */
.board-blade { display: flex; align-items: center; gap: 6px; background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  padding: 2px 10px; color: var(--fg); font-size: 12px; white-space: nowrap; }
.board-blade[aria-expanded="true"] { border-color: var(--gold); }
.blade-panel { position: fixed; top: 40px; left: 50%; transform: translateX(-50%); z-index: 70; width: min(360px, calc(100vw - 16px)); }
.blade-panel[hidden] { display: none; }
.blade-items { display: flex; flex-direction: column; }
.blade-items .where { font: 11px var(--mono); color: var(--faint); padding: 4px 10px 8px; text-transform: uppercase; letter-spacing: .08em; }
.blade-confirm { display: flex; align-items: center; gap: 6px; padding: 6px 10px; font-size: 13px; }
.app .topbar[hidden] { display: none; }
/* Without its own bar (KITE carries its menu), the table takes the whole window. */
.app:has(> .topbar[hidden]) { grid-template-rows: minmax(0, 1fr); }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .win.app-board .win-bar { display: none; }
  .board-blade { padding: 2px 8px; }
  .board-blade .label { display: none; }
  .topbar-kite.at-table .tb-right > .ghost.small { display: none; }
}

/* The dock steps aside when the player isn't at the desktop. The KITE
   launcher carries a dot for anything waiting meanwhile. */
.viewer.front-max .dock { display: none; }
.kite-button { position: relative; }
.kite-dot { display: none; position: absolute; top: 2px; right: 2px; width: 7px; height: 7px; border-radius: 50%; background: #9fd3ff; }
.viewer.front-max .kite-dot { display: block; }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .viewer.front-open .dock { display: none; }
  .viewer.front-open .kite-dot { display: block; }
}

/* The middle of KITE's bar belongs to the program in front; the station time
   sits by the account, where status lives. */
.tb-app { flex: none; display: flex; align-items: center; justify-content: center; min-width: 0; }
.tb-front { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--fg); white-space: nowrap; }
.tb-right .tb-clock { margin-left: 4px; }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) { .tb-front { font-size: 0; gap: 0; } }

/* --- the grip drawer: on a small screen the hand waits below the table ------ */
.grip-inline { display: contents; }
.grip-tab { display: none; }
@media (max-width: 820px), (max-height: 500px) and (orientation: landscape) {
  /* The rig gets the row the hand used: its bays wrap instead of scrolling away. */
  .rigbay { overflow: visible; }
  .module { flex: 1; min-width: 0; flex-wrap: wrap; row-gap: 12px; }
  .row.grip.tucks { container-type: normal; align-items: stretch; }
  /* Tucked, the grip is a tab: the cards' top edges, peeking out of the deck. */
  .grip-tab { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 40px; padding: 4px 12px; border-radius: 10px;
    background: linear-gradient(180deg, #1c1a18, #12100f); border: 1px solid #2f2b27; color: var(--fg); font: 600 13px var(--mono); text-align: left; }
  .grip-tab[aria-expanded="true"] { border-color: var(--runner); }
  .grip-name { flex: none; color: #b9afa5; letter-spacing: .08em; text-transform: uppercase; font-size: 11px; }
  .grip-name b { color: var(--fg); font-size: 13px; margin-left: 4px; }
  .grip-peek { flex: 1; min-width: 0; display: flex; gap: 4px; overflow: hidden; }
  .grip-peek i { flex: none; width: 26px; height: 20px; border-radius: 3px 3px 0 0; background: #2a2724 center top / cover no-repeat; box-shadow: inset 0 0 0 1px rgba(255,255,255,.12); opacity: .65; }
  .grip-peek i.playable { opacity: 1; box-shadow: inset 0 0 0 1px var(--runner), 0 0 6px color-mix(in oklab, var(--runner) 50%, transparent); }
  .grip-play { flex: none; color: var(--runner); font-size: 11.5px; }
  .grip-caret { flex: none; color: #b9afa5; }
  /* Open, the hand slides up over the table at a size worth reading. */
  .grip-scrim { position: fixed; inset: 0 0 var(--grip-dock, 0px); z-index: 13; background: rgba(0,0,0,.45); animation: fade var(--t-med) var(--ease-out); }
  .grip-drawer { --card-w: min(23vw, 25vh, 116px); position: fixed; left: 0; right: 0; bottom: var(--grip-dock, 0px); z-index: 14; container-type: inline-size;
    padding: 8px 10px 10px; border-radius: 18px 18px 0 0;
    background: radial-gradient(120% 140% at 50% 0%, #2a2724 0%, #1d1b19 55%, #161413 100%); border-top: 1px solid #3a3531; box-shadow: 0 -18px 40px rgba(0,0,0,.75);
    transform: translateY(105%); visibility: hidden; transition: transform var(--t-med) var(--ease-out), visibility 0s linear var(--t-med); }
  .grip-drawer.open { transform: none; visibility: visible; transition: transform var(--t-med) var(--ease-out); }
  .drawer-head { display: flex; align-items: center; gap: 10px; padding: 0 2px 2px; font-size: 13px; }
  .drawer-head b { color: var(--runner); letter-spacing: .06em; text-transform: uppercase; font-size: 12px; }
  .drawer-head span { flex: 1; min-width: 0; color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .grip-drawer .hand { padding: calc(var(--card-h) * .16) 6px 4px; }
  .is-running .row.grip { opacity: 1; }
}
@keyframes fade { from { opacity: 0; } }

/* --- The work portals: Freight Audit and Sightline -------------------------
   Both are dull thick clients around a task: a head, stats, a queue, the work
   and a side panel. Each app sets its own palette on these tokens. */
.portal { flex: 1; min-height: 0; display: grid; grid-template-rows: auto auto minmax(0, 1fr); container: portal / inline-size; background: var(--wp-bg); color: var(--wp-ink); font-size: 13px; }
.freight { --wp-bg: #14110f; --wp-panel: #181411; --wp-head: #1d1915; --wp-line: #2a241f; --wp-edge: #3a322a; --wp-ink: #e9e2d8; --wp-dim: #b3a898; --wp-faint: #8a7f72;
  --wp-mid: #9d9285; --wp-hover: #221d18; --wp-current: #2a221b; --wp-btn: #241e19; }
.wp-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; padding: 8px 12px; background: var(--wp-head); border-bottom: 1px solid var(--wp-edge); }
.wp-brand { color: var(--wp-dim); font: 11.5px var(--mono); }
.wp-brand b { color: var(--accent); letter-spacing: .12em; margin-right: 6px; }
.wp-who { margin-left: auto; color: var(--wp-dim); font: 11.5px var(--mono); }
.wp-stats { display: flex; flex-wrap: wrap; gap: 4px 18px; padding: 6px 12px; border-bottom: 1px solid var(--wp-line); color: var(--wp-mid); font: 11.5px var(--mono); }
.wp-stats b { color: var(--wp-ink); }
.wp-seat { margin-left: auto; }
.wp-main { min-height: 0; display: grid; grid-template-columns: minmax(170px, 210px) minmax(0, 1fr) minmax(160px, 200px); }
.wp-label { margin: 0 0 6px; color: var(--wp-faint); font: 600 10.5px var(--mono); letter-spacing: .12em; text-transform: uppercase; }
.wp-dim { margin: 0; color: var(--wp-faint); font-size: 12px; }
.wp-n { color: var(--wp-mid); font: 11px var(--mono); }
.wp-orders, .wp-side { min-height: 0; overflow: auto; padding: 10px; background: var(--wp-panel); }
.wp-orders { border-right: 1px solid var(--wp-line); }
.wp-side { border-left: 1px solid var(--wp-line); }
.wp-orders ul, .wp-side ul { list-style: none; margin: 0 0 14px; padding: 0; display: grid; gap: 4px; }
.wp-order { width: 100%; display: grid; grid-template-columns: 1fr auto; gap: 1px 8px; text-align: left; padding: 6px 8px; border-radius: 6px; background: transparent; border: 1px solid transparent; color: inherit; font: inherit; }
.wp-order:hover { background: var(--wp-hover); }
.wp-order.current { background: var(--wp-current); border-color: color-mix(in oklab, var(--accent) 55%, transparent); }
.wp-order b { font: 600 12px var(--mono); }
.wp-order > span:nth-child(2) { grid-column: 1 / -1; grid-row: 2; color: var(--wp-dim); font-size: 12px; }
.wp-order .wp-n { grid-column: 1 / -1; grid-row: 3; white-space: nowrap; }
.wp-order .wp-status { grid-column: 2; grid-row: 1; justify-self: end; color: var(--wp-mid); font: 10.5px var(--mono); }
.wp-order .wp-status.ok { color: #8fd18a; }
.wp-work { min-width: 0; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; container-type: inline-size; }
.wp-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.wp-toolbar b { font: 600 13px var(--mono); }
.wp-site { color: var(--wp-dim); }
.wp-tools { margin-left: auto; display: flex; gap: 6px; }
.wp-tools button, .wp-back { padding: 3px 10px; border-radius: 5px; background: var(--wp-btn); border: 1px solid var(--wp-edge); color: inherit; font: 12px var(--mono); }
.wp-tools button:disabled { opacity: .45; }
.wp-back { display: none; }
/* The plan: drawn tiles, never photos. Cells size to the panel. */
.fa-plan { --cell: min(52px, calc((100cqw - 4px) / var(--w))); align-self: center; display: grid; grid-template-columns: repeat(var(--w), var(--cell)); grid-auto-rows: var(--cell);
  padding: 2px; border-radius: 6px; outline: none; touch-action: manipulation; user-select: none; }
.fa-plan:focus-visible { box-shadow: 0 0 0 2px var(--accent); }
.fa-cell { position: relative; display: grid; place-items: center; }
.fa-cell.floor { background: #2b2620; box-shadow: inset 0 0 0 1px #241f1a; cursor: pointer; }
.fa-cell.wall { background: linear-gradient(135deg, #4a4239, #3a332c); box-shadow: inset 0 0 0 1px #2a241f, inset 0 -3px 0 #2a241f; }
.fa-cell.bay::before { content: ""; position: absolute; inset: 18%; border: 2px dashed #e0a43a; border-radius: 3px; opacity: .8; }
.crate { position: relative; z-index: 1; width: 84%; height: 84%; border-radius: 3px; display: block; }
.crate.timber { background: linear-gradient(45deg, transparent 46%, #6a4522 46% 54%, transparent 54%), repeating-linear-gradient(0deg, #b07a43 0 22%, #946233 22% 25%); box-shadow: inset 0 0 0 2px #5d3b1c; }
.crate.steel { background: radial-gradient(circle at 16% 16%, #c9d2d8 0 6%, transparent 7%), radial-gradient(circle at 84% 16%, #c9d2d8 0 6%, transparent 7%), radial-gradient(circle at 16% 84%, #c9d2d8 0 6%, transparent 7%), radial-gradient(circle at 84% 84%, #c9d2d8 0 6%, transparent 7%), linear-gradient(180deg, #7d8992, #5b666e);
  box-shadow: inset 0 0 0 2px #3e474e; }
.crate.reefer { background: repeating-linear-gradient(90deg, transparent 0 18%, #9cc3cf 18% 22%), linear-gradient(180deg, #e8eef0, #c8d3d7); box-shadow: inset 0 0 0 2px #7f969e; }
.crate.reefer::after { content: ""; position: absolute; right: 12%; top: 14%; width: 22%; height: 18%; border-radius: 2px; background: #3aa6c8; }
.crate.drum { width: 74%; height: 74%; border-radius: 50%; background: radial-gradient(circle, #2f6db3 0 38%, #24578f 39% 46%, #2f6db3 47% 70%, #1d4473 71%); box-shadow: inset 0 0 0 2px #163659; }
.crate.home { box-shadow: inset 0 0 0 2px #3f8a3a, 0 0 0 2px #8fd18a; }
.crate.drum.home { box-shadow: inset 0 0 0 2px #163659, 0 0 0 2px #8fd18a; }
.crate.mini { width: 18px; height: 18px; flex: none; }
.mover { position: relative; z-index: 2; width: 62%; height: 62%; border-radius: 30%; background: var(--accent); box-shadow: inset 0 -3px 0 rgba(0,0,0,.25), 0 2px 4px rgba(0,0,0,.5); display: block; }
.mover::after { content: ""; position: absolute; left: 50%; top: -22%; width: 18%; height: 30%; margin-left: -9%; border-radius: 2px; background: #2a2016; }
.mover.face-right { transform: rotate(90deg); } .mover.face-down { transform: rotate(180deg); } .mover.face-left { transform: rotate(-90deg); }
.wp-line { margin: 0; text-align: center; color: var(--wp-dim); font: 12px var(--mono); }
.wp-report { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 8px 10px; border-radius: 6px; background: #1f2a1c; border: 1px solid #3f6a3a; }
.wp-report p { margin: 0; flex: 1 1 260px; font: 12.5px var(--mono); color: #cfe8c9; }
.wp-hint { margin: 0; color: var(--wp-faint); font-size: 12px; text-align: center; }
.wp-manifest li, .wp-ledger li { display: flex; align-items: center; gap: 8px; }
.wp-manifest li .wp-n, .wp-ledger li .wp-n { margin-left: auto; }
.wp-ledger li b { font: 600 12px var(--mono); }
.wp-ledger li span:not(.wp-n) { color: var(--wp-mid); font-size: 12px; }
/* A narrow window: the plan alone, with the orders a tap away; the manifest and ledger follow it. */
@container portal (max-width: 640px) {
  .wp-main { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; overflow: auto; }
  .wp-orders { display: none; border-right: 0; }
  .portal.view-orders .wp-orders { display: block; }
  .portal.view-orders .wp-work { display: none; }
  .wp-back { display: inline-block; }
  .wp-side { border-left: 0; border-top: 1px solid var(--wp-line); overflow: visible; }
  .wp-work { overflow: visible; }
  .wp-seat, .wp-who { margin-left: 0; }
}
.wp-main.wp-empty { display: flex; flex-direction: column; gap: 8px; padding: 18px 20px; }
.wp-main.wp-empty p { margin: 0; }

/* Sightline: a cool contributor console, and its floor plans drawn as
   blueprints. Seen cells take the console's violet; sensors are camera domes. */
.sightline { --wp-bg: #0e1016; --wp-panel: #11131b; --wp-head: #151826; --wp-line: #1f2333; --wp-edge: #2c3147; --wp-ink: #e3e6f2; --wp-dim: #a6abc3; --wp-faint: #767c96;
  --wp-mid: #8d93ad; --wp-hover: #181b28; --wp-current: #1d2033; --wp-btn: #181b29; }
.sl-plan { --cell: min(52px, calc((100cqw - 4px) / var(--w))); align-self: center; display: grid; grid-template-columns: repeat(var(--w), var(--cell)); grid-auto-rows: var(--cell);
  padding: 2px; border-radius: 6px; outline: none; touch-action: manipulation; user-select: none; background: #070910; }
.sl-plan:focus-visible { box-shadow: 0 0 0 2px var(--accent); }
.sl-cell { position: relative; display: grid; place-items: center; }
.sl-cell.floor { background: #121726; box-shadow: inset 0 0 0 1px #1b2134; cursor: pointer; transition: background var(--t-fast, .12s); }
.sl-cell.floor.lit { background: color-mix(in oklab, var(--accent) 22%, #121726); }
.sl-cell.wall { background: repeating-linear-gradient(45deg, #2a3045 0 3px, #1a1e2c 3px 7px); box-shadow: inset 0 0 0 1px #353b54; }
.sl-cell.wall:has(b) { background: #262b3d; }
.sl-cell.wall b { font: 700 15px var(--mono); color: #c9cde0; }
.sl-cell.wall.met b { color: #8fd18a; }
.sl-cell.wall.over b { color: #ff6b78; }
.sl-plan:focus-visible .sl-cell.cursor { box-shadow: inset 0 0 0 2px var(--accent); }
.sensor { width: 58%; height: 58%; border-radius: 50%; display: block; background: radial-gradient(circle at 50% 58%, #10131d 0 26%, #e9dcff 27% 34%, var(--accent) 35% 100%);
  box-shadow: 0 0 10px color-mix(in oklab, var(--accent) 60%, transparent), inset 0 -2px 0 rgba(0,0,0,.25); }
.sensor.clash { background: radial-gradient(circle at 50% 58%, #10131d 0 26%, #ffd6da 27% 34%, #ff5d6c 35% 100%); box-shadow: 0 0 10px rgba(255,93,108,.6); }
.sl-bad { color: #ff6b78; }

/* --- The Meridian access desk: Catalyst's console ---------------------------
   Dense and monospace. Routine rows stay quiet so an open or refused ticket,
   and the line that needs a decision, carry the emphasis. */
.desk { flex: 1; min-height: 0; display: grid; grid-template-rows: auto auto auto minmax(60px, 1fr) auto auto; background: #0a0f0d; color: #d6e2dc;
  font: 13px/1.45 var(--mono); outline: none; }
.desk:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.desk-head { display: flex; align-items: baseline; gap: 6px; padding: 8px 12px; border-bottom: 1px solid #1d2a25; background: #0d1512; }
.desk-head b { color: var(--accent); letter-spacing: .14em; }
.desk-head span { color: #8fa69b; }
.desk-when { margin-left: auto; color: #d6e2dc !important; }
.desk-queue { list-style: none; margin: 0; padding: 4px 0; overflow: auto; max-height: 11.5em; border-bottom: 1px solid #1d2a25; }
.desk-row { width: 100%; display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; gap: 8px; align-items: baseline; padding: 3px 12px; border: 0; background: none;
  color: #8fa69b; font: inherit; text-align: left; }
.desk-row:hover { background: #111c18; }
.desk-row.current { background: #13211c; color: #d6e2dc; }
.desk-row.s-open, .desk-row.s-alert { color: #eef4f0; }
.desk-row.s-alert .desk-mark, .desk-row.s-alert .desk-state { color: #ff8a7a; }
.desk-row.s-open .desk-mark, .desk-row.s-open .desk-state { color: #f2c46d; }
.desk-row.s-done .desk-mark { color: #6fbf8e; }
.desk-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.desk-state { font-size: 11.5px; color: #6f8479; }
.desk-ticket { padding: 8px 12px 10px; border-bottom: 1px solid #1d2a25; background: #0c1310; }
.desk-ticket p { margin: 0 0 3px; color: #b9c9c1; }
.desk-ticket .desk-ticket-title { color: #eef4f0; font-weight: 700; margin-bottom: 6px; }
.desk-ticket.s-open .desk-ticket-title span { color: #f2c46d; }
.desk-ticket.s-alert .desk-ticket-title span { color: #ff8a7a; }
.desk-ticket.s-done .desk-ticket-title span { color: #6fbf8e; }
.desk-log { list-style: none; margin: 0; padding: 6px 12px; overflow: auto; color: #8fa69b; font-size: 12px; }
.desk-log li::before { content: "› "; color: #3f5a4e; }
.desk-log li:last-child::before { content: none; }
.desk-log li.person, .desk-log li.agent { color: #d6e2dc; }
.desk-log .composing { font-style: italic; }
.desk-commands { display: flex; flex-wrap: wrap; gap: 2px 18px; padding: 6px 12px 8px; border-top: 1px solid #1d2a25; }
.desk-commands .keycap { color: #eef4f0; }
.desk-foot { display: flex; gap: 18px; padding: 5px 12px; border-top: 1px solid #1d2a25; background: #0d1512; color: #8fa69b; font-size: 12px; }
.desk-foot b { color: #eef4f0; }
.desk-relay { margin-left: auto; }
@media (max-width: 720px) {
  .desk-commands { flex-direction: column; gap: 0; }
  .desk-commands .keycap { padding: 8px 4px; }
}

/* The work views say, quietly, who built them: Catalyst, with Latch. */
.wp-view, .desk-view { color: var(--wp-faint, #6f8479) !important; font-size: 11px; }
@container portal (max-width: 640px) { .wp-view { display: block; } }
@media (max-width: 720px) { .desk-view { display: none; } }
/* Labels on the bright groundside sky keep a soft backing; a phone's crop
   leans toward the sun. */
.desk-files li span { background: rgba(5, 8, 14, .45); border-radius: 4px; padding: 1px 4px; color: #e6ebf2; }
@media (max-width: 720px) { .wallpaper.home { background-position: center, 80% center; } }

/* --- Files: the deck's disk ------------------------------------------------ */
.files-places { gap: 0; }
.files-place { display: contents; }
.files-places button { background: none; border: 0; color: var(--dim); font: inherit; text-align: left; padding: 3px 6px; border-radius: 5px; }
.files-places button:hover { color: var(--fg); background: var(--panel-2); }
.files-places button.current { color: var(--fg); background: var(--panel-2); }
.files-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.files-path { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; font: 13px var(--mono); }
.files-path button { background: none; border: 0; padding: 1px 3px; color: var(--fg); font: inherit; border-radius: 4px; }
.files-path button:hover { background: var(--panel-2); }
.files-path .sep { color: var(--faint); }
.files-home { font-size: 12px; white-space: pre; }
.files-hidden { font-size: 12px; color: var(--dim); display: flex; gap: 5px; align-items: center; }
.files-note { margin: 0; font-size: 12px; }
.file-list .fname { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.file-list .fname > span { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.file-list .fname small { font-size: 11.5px; }
.file-list .fmeta { flex: none; font-size: 12px; text-align: right; max-width: 45%; }
.file-list button.damaged .fname > span:first-of-type, .file-list button.damaged { color: var(--dim); }
.file-list button.dotfile { opacity: .75; }
.fglyph { flex: none; margin-top: 2px; color: var(--dim); }
.fglyph.k-folder { color: var(--accent, #9fd3ff); }
.fglyph.k-damaged { color: #d98b7a; }
.fglyph.k-encrypted { color: #d6b26a; }
.files-status { margin: 0; padding: 6px 10px; border-radius: 6px; background: var(--panel-2); font-size: 13px; }
.files-viewer { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.files-viewer header { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; padding: 6px 10px; background: var(--panel-2); font-size: 13px; }
.files-viewer header .ghost { margin-left: auto; }
.files-viewer pre { margin: 0; padding: 10px 12px; font: 12.5px/1.55 var(--mono); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 50vh; overflow: auto; }
/* A text file keeps its lines, as a text viewer does: long ones scroll. */
.files-viewer pre { white-space: pre; overflow-wrap: normal; overflow-x: auto; }
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .files-places { flex-wrap: nowrap; overflow-x: auto; padding: 6px 8px; gap: 2px; }
  .files-places b { display: none; }
  .files-places button { white-space: nowrap; }
  .file-list .fmeta { max-width: 40%; }
}
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .files { grid-template-rows: auto minmax(0, 1fr); }
  .files-places { align-items: center; align-self: start; }
}

/* --- Ads on the sponsored plan --------------------------------------------- */
.ad-art { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 6px; }
.ad-art.placeholder { display: grid; place-items: end start; padding: 8px 10px; box-sizing: border-box; color: #fff;
  background: radial-gradient(120% 90% at 20% 10%, color-mix(in oklab, var(--tint) 70%, #fff), var(--tint) 55%, color-mix(in oklab, var(--tint) 55%, #000)); }
.ad-art.placeholder b { font: 700 13px var(--mono); letter-spacing: .06em; text-shadow: 0 1px 2px rgba(0,0,0,.4); }
.notice-art { grid-column: 1 / -1; margin: 4px 0 2px; aspect-ratio: 16 / 9; }
.upsell { display: grid; grid-template-columns: minmax(0, 180px) minmax(0, 1fr); gap: 12px; padding: 12px; border-radius: 10px;
  background: linear-gradient(135deg, #fff7d6, #ffe1f0 55%, #dfe9ff); color: #1d2340; border: 1px solid #f2c94c; }
.upsell-art { aspect-ratio: 1 / 1; }
.upsell-copy { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.upsell-tag { font: 10.5px var(--mono); letter-spacing: .08em; text-transform: uppercase; color: #6a6f8f; }
.upsell-copy b { font: 800 17px/1.2 system-ui, sans-serif; color: #1d2340; }
.upsell-copy p { margin: 0; font-size: 13px; color: #34395c; }
.upsell-keys { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 4px; }
.upsell-cta { border: 0; border-radius: 999px; padding: 7px 14px; font: 700 13px system-ui, sans-serif; color: #fff;
  background: linear-gradient(90deg, #ff4f8b, #ff8a3d); box-shadow: 0 2px 8px rgba(255,79,139,.4); cursor: pointer; }
.upsell-keys .ghost { color: #4b5070; }
.upsell-trial { color: #9a3d14 !important; }
.upsell small { font-size: 10.5px; color: #6a6f8f; line-height: 1.35; }
@media (max-width: 720px) { .upsell { grid-template-columns: 1fr; } .upsell-art { aspect-ratio: 16 / 9; } }

/* --- The free PDF reader (fictional documents) ----------------------------- */
.pdf { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; }
.pdf-bar { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; padding: 6px 10px; background: var(--panel-2); font-size: 13px; }
.pdf-bar .ghost { margin-left: auto; }
.pdf-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; padding: 6px 10px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); font-size: 12.5px; }
.pdf-page { font: 12px var(--mono); color: var(--dim); font-variant-numeric: tabular-nums; }
.pdf-sep { width: 1px; height: 16px; background: var(--line); margin: 0 4px; }
.pdf-tool { display: inline-flex; align-items: center; gap: 5px; background: none; border: 1px solid transparent; border-radius: 5px; padding: 3px 7px; color: var(--dim); font: inherit; cursor: pointer; }
.pdf-tool:hover { border-color: var(--line); color: var(--fg); }
.pro { display: inline-block; padding: 0 5px; border-radius: 999px; font: 700 9.5px/1.6 system-ui, sans-serif; letter-spacing: .04em; text-transform: uppercase; color: #fff;
  background: linear-gradient(90deg, #ff4f8b, #ff8a3d); }
.pdf-scan { margin: 0; padding: 6px 10px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; background: #fff7d6; color: #5a4a12; font-size: 12.5px; }
.pdf-scan .pdf-tool { color: #5a4a12; border-color: #e7cf7a; }
.pdf-stage { background: #50555d; padding: 16px; overflow: auto; max-height: 60vh; }
.pdf-sheet { --zoom: 1; box-sizing: border-box; width: calc(min(560px, 100%) * var(--zoom)); max-width: none; margin: 0 auto; min-height: calc(min(560px, 100%) * var(--zoom) * 1.3); background: #fdfcf8; color: #1b1d22;
  padding: calc(28px * var(--zoom)) calc(30px * var(--zoom)); box-shadow: 0 4px 18px rgba(0,0,0,.35); font: calc(12.5px * var(--zoom))/1.5 Georgia, "Times New Roman", serif; display: flex; flex-direction: column; gap: .7em; }
.pdf-sheet.scanned { background: #e9e7e1; }
.pdf-head { border-bottom: 2px solid #1b1d22; padding-bottom: .4em; margin-bottom: .3em; }
.pdf-head h4 { margin: 0; font: 700 1.35em/1.2 system-ui, sans-serif; }
.pdf-head span { font: .9em system-ui, sans-serif; color: #50545d; }
.pdf-sheet p { margin: 0; }
.pdf-stamp { align-self: flex-start; transform: rotate(-4deg); border: 3px double #b0412f; color: #b0412f; padding: .15em .6em; font: 700 1.05em system-ui, sans-serif; text-transform: uppercase; letter-spacing: .06em; }
.pdf-field { display: grid; grid-template-columns: 11em minmax(0, 1fr); gap: .8em; border-bottom: 1px dotted #9a9da3; padding-bottom: .25em; }
.pdf-field span, .pdf-sign span { font: .85em system-ui, sans-serif; color: #50545d; text-transform: uppercase; letter-spacing: .03em; }
.pdf-field b { font-weight: 400; font-family: "Courier New", monospace; }
.pdf-blank { justify-self: start; display: inline-flex; align-items: center; gap: .4em; background: #eef3ff; border: 1px dashed #7d93d6; border-radius: 3px; padding: .1em .5em; color: #4b5d96; font: italic .9em system-ui, sans-serif; cursor: pointer; }
.pdf-sign { display: grid; gap: .3em; margin-top: 1em; }
.pdf-signed { font: italic 1.4em "Brush Script MT", "Segoe Script", cursive; color: #233a7a; border-bottom: 1px solid #1b1d22; }
.pdf-blank.sign { padding: .6em 1em; }
.pdf-rows { border-collapse: collapse; width: 100%; font-family: system-ui, sans-serif; font-size: .95em; }
.pdf-rows th, .pdf-rows td { border-bottom: 1px solid #d9d8d2; padding: .3em .2em; text-align: left; }
.pdf-rows th { font-weight: 400; color: #50545d; }
.scan-page { display: flex; flex-direction: column; gap: 1.1em; padding-top: 1.5em; }
.scan-page i { display: block; height: .55em; background: #c9c6be; border-radius: 2px; filter: blur(.6px); }
@media (max-width: 720px) { .pdf-field { grid-template-columns: 1fr; gap: .1em; } .pdf-stage { padding: 8px; } }

/* Entering a persona's profile shows Spool's watch on its work queue. */
.unlocked .keeper { display: inline-flex; align-items: center; gap: 6px; padding-left: 8px; border-left: 1px solid var(--line); color: var(--fg) !important; }
.unlocked .keeper i { width: 7px; height: 7px; border-radius: 50%; background: #a8c8ff; box-shadow: 0 0 6px #a8c8ff; animation: live 1s ease-in-out infinite alternate; }
@media (prefers-reduced-motion: reduce) { .unlocked .keeper i { animation: none; } }
@media (max-width: 720px) { .unlocked { flex-wrap: wrap; justify-content: center; max-width: calc(100vw - 24px); } .unlocked .keeper { border-left: 0; padding-left: 0; } }

/* --- Printed cards in the default card style set's layout (PrintedLayout.tsx).
   Every size is in container units of the card's own width (--u is a
   hundredth of its short side), so one layout draws up close and at table
   size alike. Layouts come from Card Studio (assets/card-layouts). */
.lp-box { container-type: inline-size; width: 100%; }
.lp-wide-box { aspect-ratio: 88 / 63; position: relative; }
.lp { --u: 1cqw; position: relative; box-sizing: border-box; width: 100%; aspect-ratio: 63 / 88; overflow: hidden; display: flex; flex-direction: column;
  gap: calc(var(--u) * 1.6); padding: calc(var(--u) * var(--k-inset)); border-radius: calc(var(--u) * var(--k-radius));
  border: calc(var(--u) * var(--k-border)) solid var(--edge); background-color: var(--paper); color: var(--ink);
  font: calc(var(--u) * 4.4) / 1.3 var(--text-font); text-align: left; }
.lp.lp-wide { --u: calc(1cqw * 63 / 88); aspect-ratio: 88 / 63; flex-direction: row; }
.lp-rot { position: absolute; left: 50%; top: 50%; width: calc(100cqw * 63 / 88); container-type: inline-size; transform: translate(-50%, -50%) rotate(90deg); }
.lp-tex-grain { background-image: radial-gradient(rgba(127,127,127,.18) 1px, transparent 1.2px); background-size: calc(var(--u) * 1.6) calc(var(--u) * 1.6); }
.lp-tex-halftone { background-image: radial-gradient(rgba(127,127,127,.22) 32%, transparent 34%); background-size: calc(var(--u) * 2.4) calc(var(--u) * 2.4); }
.lp-tex-linen { background-image: repeating-linear-gradient(0deg, rgba(127,127,127,.09) 0 1px, transparent 1px 3px), repeating-linear-gradient(90deg, rgba(127,127,127,.09) 0 1px, transparent 1px 3px); }
.lp-tex-scan { background-image: repeating-linear-gradient(0deg, rgba(0,0,0,.18) 0 1px, transparent 1px 3px); }
.lp-art { position: relative; flex: none; height: var(--art-h); background: #1a2230 center / cover; border-radius: calc(var(--u) * var(--k-art-radius)); overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end; }
.lp-art.lp-art-fill { flex: 1 1 auto; height: auto; }
.lp-wide .lp-art { height: auto; width: 52%; }
.lp-head { display: flex; align-items: center; gap: .4em; flex: none; padding: .35em .5em; border-radius: calc(var(--u) * var(--k-art-radius) + 2px); font-family: var(--title-font); }
.lp-ts-bar .lp-head, .lp-fit-bleed .lp-head { background: var(--panel-bg, var(--panel)); }
.lp-ts-band .lp-head { background: var(--edge); color: var(--paper); }
.lp-ts-plain .lp-head { padding-inline: .1em; }
.lp-name { margin: 0; flex: 1; min-width: 0; font-size: 1.3em; line-height: 1.1; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp-case-upper .lp-name { text-transform: uppercase; letter-spacing: .05em; }
.lp-case-smallcaps .lp-name { font-variant: small-caps; letter-spacing: .04em; }
.lp-glyph { width: 1.4em; height: 1.4em; object-fit: contain; flex: none; }
.lp-cost-inline { display: inline-flex; align-items: center; gap: .15em; font-size: 1.2em; }
.lp-cost-inline .sym { width: .95em; height: .95em; color: var(--accent); }
.lp-stripe-title .lp-head { box-shadow: inset 0 -2px 0 var(--faction); }
.lp-stripe { position: absolute; background: var(--faction); pointer-events: none; }
.lp-stripe-left .lp-stripe { left: 0; top: 0; bottom: 0; width: calc(var(--u) * 2.2); }
.lp-stripe-top .lp-stripe { left: 0; right: 0; top: 0; height: calc(var(--u) * 2.2); }
.lp-body { display: flex; flex-direction: column; gap: .3em; flex: 1 1 auto; min-height: 0; overflow: hidden; }
.lp-art > .lp-body, .lp-over > .lp-body { flex: none; max-height: 60%; padding: .5em .6em; background: var(--panel-bg, var(--panel)); border-radius: calc(var(--u) * var(--k-art-radius)); }
.lp-art > .lp-body { margin: calc(var(--u) * 2); }
.lp-type { font: 700 .72em var(--title-font); letter-spacing: .08em; text-transform: uppercase; color: color-mix(in oklab, var(--tone) 55%, var(--ink)); }
.lp-text { font-size: calc(.92em * var(--text-size)); line-height: 1.32; overflow: hidden; }
.lp-text p { margin: 0 0 .3em; }
.lp-text p.sub { display: flex; gap: .35em; }
.lp-text .sym { flex: none; width: 1em; height: 1em; margin-top: .15em; color: var(--tone); }
.lp-text .none { opacity: .6; }
.lp-text-below .lp-text { padding: .45em .55em; background: var(--panel-bg, var(--panel)); border-radius: calc(var(--u) * var(--k-art-radius)); flex: 1 1 auto; }
.lp-foot { display: flex; align-items: center; gap: .6em; flex: none; font-size: .8em; min-height: 1.6em; }
.lp-fit-bleed .lp-foot { background: var(--panel-bg, var(--panel)); padding: .2em .5em; border-radius: calc(var(--u) * var(--k-art-radius)); }
.lp-stat { display: inline-flex; gap: .2em; align-items: center; }
.lp-stat b { font-size: 1.35em; }
.lp-stat small { font: 700 .75em var(--title-font); letter-spacing: .08em; opacity: .75; }
.lp-stat .sym { width: 1.1em; height: 1.1em; color: var(--tone); }
.lp-set { margin-left: auto; opacity: .6; font: .8em var(--title-font); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lp-col { display: flex; flex-direction: column; gap: calc(var(--u) * 1.6); flex: 1 1 0; min-width: 0; }
.lp-fit-bleed { padding: 0; }
.lp-fit-bleed > .lp-art { position: absolute; inset: 0; height: auto; width: auto; border-radius: 0; }
.lp-over { position: relative; z-index: 1; flex: 1; display: flex; flex-direction: column; gap: calc(var(--u) * 1.4); padding: calc(var(--u) * 3); min-width: 0; }
.lp-wide .lp-over { margin-left: 45%; background: var(--panel-bg, var(--panel)); }
.lp-spacer { flex: 1 1 auto; }
.lp-cost { position: absolute; z-index: 3; display: grid; place-items: center; font: 800 1.35em var(--title-font); }
.lp-cost-coin { top: calc(var(--u) * 2); left: calc(var(--u) * 2); width: 2em; height: 2em; font-size: 1.2em; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffe08a, var(--gold) 60%, #b98a2a); color: #141006; box-shadow: 0 0 0 2px #0b0f13, 0 2px 5px #0009; }
.lp-cost-tab { top: 0; left: 12%; padding: .35em .6em .25em; background: var(--edge); color: var(--paper); border-radius: 0 0 .35em .35em; }
.lp-cost-corner { top: calc(var(--u) * 2); right: calc(var(--u) * 2); min-width: 1.5em; height: 1.5em; padding: 0 .2em; font-size: 1.6em; background: var(--paper); border-radius: 0 0 0 .35em; }
.lp-has-coin .lp-head:first-child, .lp-has-coin .lp-over > .lp-head:first-child { padding-left: 2.8em; }
.lp-has-corner .lp-head:first-child, .lp-has-corner .lp-over > .lp-head:first-child { padding-right: 2.6em; }
.lp-orn { position: absolute; z-index: 2; width: calc(var(--k-orn) * var(--u)); height: calc(var(--k-orn) * var(--u)); background: top left / contain no-repeat; pointer-events: none; }
.lp-orn-tl { top: 0; left: 0; } .lp-orn-tr { top: 0; right: 0; transform: scaleX(-1); }
.lp-orn-bl { bottom: 0; left: 0; transform: scaleY(-1); } .lp-orn-br { bottom: 0; right: 0; transform: scale(-1); }

/* Up close (CardReview): the printed card takes the review's card column. */
.printed-layout { width: var(--pw); align-self: end; filter: drop-shadow(0 18px 40px rgba(0,0,0,.6)); }
/* At the table: the printed card is the face's background; the table card's own
   title and foot overlay it. */
.face.face-printed { background: #0b1016; }
.face.face-printed > .lp-box { position: absolute; inset: 0; }
.face.face-printed .lp { box-shadow: none; }
.hart.hart-printed { display: block; }
.hart.hart-printed > .lp-box { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
.hart.hart-printed .lp { height: 100%; aspect-ratio: auto; }
