/* Pickle Arcade: the site register.
 *
 * The estate's ground, type and chrome are shared-ui's. This file adds the
 * cabinet grammar every page shares: a 2px tube of light that strikes on load,
 * a screen that turns on, a plate of light on the floor, the coin slot and the
 * unlit 404. The hall's house, the tickets, the wallet's door and the fair
 * page's line live here. Everything the arena page alone asks for lives in
 * arena.css, which loads after this one and reads the tokens below.
 *
 * The site accent stays mint, deliberately: re-grounding it the way pepper.css
 * does would recolour .ex-pill.mint on a site that also shows chain-status
 * pills. The three lights below are per-cabinet, never the page accent. */

/* ==================================================================== tokens
 * All on the body, none on :root. --pickle-accent-text is a registered
 * @property and is never redeclared here: accent text reads it and gets the
 * same mint the rest of the estate does. */
body[data-app="minigame"] {
  --arc-arena: #00e788;
  --arc-crash: #f4a300;
  --arc-claw: #9b6bff;
  /* 100dvh rather than 100vh, because on a phone vh is the viewport WITHOUT the
     browser chrome and the stage would be taller than the screen. */
  --arc-stage: calc(100dvh - var(--pickle-nav-h) - var(--pickle-bar-h));
  /* Under 1024px the deck must sit on the first screen beside the stage. */
  --arc-stage-phone: min(var(--arc-stage), 66dvh);
  --arc-arena-hi: #7dffbf;
  --arc-arena-dim: #12db86;
  --arc-crash-hi: #ffc861;
  --arc-claw-hi: #c9b3ff;
  --arc-tube-arena: rgb(0 231 136 / 90%);
  --arc-tube-crash: rgb(244 163 0 / 90%);
  --arc-tube-claw: rgb(155 107 255 / 90%);
  --arc-glow-arena: rgb(0 231 136 / 22%);
  --arc-glow-crash: rgb(244 163 0 / 22%);
  --arc-glow-claw: rgb(155 107 255 / 22%);
  /* Equals --pickle-bg-deep: the canvas paints the same literal, so CSS and
     picture share one ground and the screen's edge is never a seam. */
  --arc-glass: #050506;
  --arc-plate: rgb(5 5 6 / 74%);
  --arc-plate-hard: rgb(5 5 6 / 88%);
  /* White, never amber: on this estate mint means confirmed and amber means
     warn, and a move in flight is neither. */
  --arc-pending: rgb(255 255 255 / 55%);
  --arc-grid: rgb(255 255 255 / 5%);
  --arc-grid-strong: rgb(255 255 255 / 9%);
  /* The nav's own gutter formula, so the house head and the console line up
     with the brand. Padding or an offset only, never a width. */
  --arc-inset: max(var(--pickle-gutter), calc((100vw - var(--pickle-content)) / 2));
  --arc-house-h: min(84dvh, 46rem);
  --arc-read: clamp(2.2rem, 4vw, 3.4rem);
  --arc-figure: clamp(1.5rem, 2.4vw, 2rem);
  --arc-coin: clamp(1.75rem, 3vw, 2.6rem);
  --arc-bar: rgb(0 231 136 / 70%);
  --arc-bar-last: #7dffbf;
  /* Rose: a refusal is an error outcome. Amber: no receipt is a warning. */
  --arc-refused: rgb(255 92 92 / 70%);
  --arc-unknown: rgb(244 163 0 / 70%);
  /* White because the median is a fact about the data, not a state. */
  --arc-median: #ffffff;
  --arc-target: rgb(0 231 136 / 35%);
}

/* Per-object light. The three modifier classes set it; .arc-tube,
   .arc-ticket-stub and .arc-door read it. */
.arc-arena { --arc-light: var(--arc-arena); --arc-light-tube: var(--arc-tube-arena); --arc-light-glow: var(--arc-glow-arena); }
.arc-crash { --arc-light: var(--arc-crash); --arc-light-tube: var(--arc-tube-crash); --arc-light-glow: var(--arc-glow-crash); }
.arc-claw  { --arc-light: var(--arc-claw);  --arc-light-tube: var(--arc-tube-claw);  --arc-light-glow: var(--arc-glow-claw); }

/* The estate's mint page glow (motion.css draws it on .ex-wrap::before) is off
   on this site, as pepper.css re-grounds it: the tubes and the stubs light the
   page, and a second mint pool behind the tickets would fight the house's. */
body[data-app="minigame"] .ex-wrap::before { display: none; }

/* ============================================================== shared type
 * The display-size mono figure: the vault, the death score, the deck's
 * milliseconds. Every figure on this estate is mono, and one page must not set
 * the same number in two faces. */
.arc-read {
  font-family: var(--pickle-font-mono);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.04em;
  line-height: .9;
  color: var(--pickle-text);
}

/* =================================================================== the tube
 * The 2px line of light along the top edge of a lit object. It strikes on load
 * (the keyframe below) and is the same element on the house, the door and the
 * arena band. Above the object's picture, under nothing else. */
.arc-tube {
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--arc-light-tube);
  z-index: 2;
  pointer-events: none;
}

/* The wallet's tube while its balances are unknown or the chain is still being
   read: amber is the estate's warn, and a vault whose figures print "-" is a
   warning before it is anything else. */
.arc-tube.amber { background: var(--arc-tube-crash); }

/* ================================================================= keyframes
 * Declared outside the motion gate so arena.css can name them too; nothing
 * moves until a gated rule uses one. */

/* A fluorescent tube catching: dim, off, then on. steps(1, end) on the rule
   that uses it, so there is no fade between the states. */
@keyframes arc-strike {
  0% { opacity: 0; }
  35% { opacity: .4; }
  50% { opacity: 0; }
  65% { opacity: 1; }
  100% { opacity: 1; }
}

/* A screen turning on: a bright line opening to the full picture. */
@keyframes arc-screen-on {
  from { transform: scaleY(.02); opacity: .6; }
  to { transform: none; opacity: 1; }
}

/* One real mini-block read lighting the bar's edge: draws left to right, then
   fades. Fired by Ribbon.jsx on each answer and never by a timer. */
@keyframes arc-beat {
  0% { opacity: 1; transform: scaleX(0); }
  30% { opacity: 1; transform: scaleX(1); }
  100% { opacity: 0; transform: scaleX(1); }
}

/* motion.css's ex-rule, restated for the house head, which sits outside
   .ex-wrap and so gets none of the estate's load rules. */
@keyframes arc-rule {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* ================================================================== live bar
 * Copied from explorer.css because components.css does not define it, scoped
 * to this origin. motion.css animates `.ex-livebar` by name. */
body[data-app="minigame"] .ex-livebar {
  position: sticky;
  top: var(--pickle-nav-h);
  z-index: var(--pickle-z-bar);
  height: var(--pickle-bar-h);
  display: flex;
  align-items: center;
  gap: var(--pickle-space-5);
  padding: 0 var(--pickle-gutter);
  border-bottom: 1px solid var(--pickle-line);
  background: var(--pickle-bg-deep);
  overflow-x: auto;
  white-space: nowrap;
  scrollbar-width: none;
}

body[data-app="minigame"] .ex-livebar::-webkit-scrollbar { height: 0; }

/* `flex: 0 0 auto` is the fix for the phone bar. base.css sets `* { min-width: 0 }`,
   so each item used to shrink below its own nowrap text and the values printed
   over the labels ("MINI-BLC8006744") while overflow-x: auto never had anything
   to scroll. An item that keeps its width makes the bar wider than the phone,
   and the bar scrolls sideways instead, which is what it was built to do. */
body[data-app="minigame"] .ex-live-item {
  display: flex;
  align-items: baseline;
  gap: var(--pickle-space-2);
  flex: 0 0 auto;
}

body[data-app="minigame"] .ex-live-item small {
  color: var(--pickle-subtle);
  font-size: var(--pickle-text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--pickle-tracking-caps);
  white-space: nowrap;
}

body[data-app="minigame"] .ex-live-item b { font-family: var(--pickle-font-mono); font-size: var(--pickle-text-sm); }
body[data-app="minigame"] .ex-live-item b.num { font-variant-numeric: tabular-nums; }

/* The mini-block figure never jitters: seven tabular digits reserved, so the
   items after it do not move when the number rolls over. Only this cell; the
   player count beside it is one or two digits and a 7ch box would leave a hole. */
body[data-app="minigame"] .ex-live-item.arc-pulse { position: relative; }
body[data-app="minigame"] .ex-live-item.arc-pulse b.num { min-width: 7ch; }

body[data-app="minigame"] .ex-live-on {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--pickle-space-2);
  flex: 0 0 auto;
  color: var(--pickle-accent-text);
  font-size: var(--pickle-text-2xs);
}

body[data-app="minigame"] .ex-live-on .ex-dot { width: 6px; height: 6px; border-radius: 50%; margin: 0; background: currentColor; }

/* Asking is not live and not down: muted words, a still white dot. */
body[data-app="minigame"] .ex-live-on.asking { color: var(--pickle-muted); }
body[data-app="minigame"] .ex-live-on.asking .ex-dot { background: rgb(255 255 255 / 40%); animation: none; }

body[data-app="minigame"] .ex-live-on.off { color: var(--pickle-amber); }

/* .ex-dot carries a global pulse from components.css. An unreachable chain
   must not keep a confident dot beating next to the words saying it is not
   there, which is why explorer.css and pepper.css both kill it in the off
   state and this does too. */
body[data-app="minigame"] .ex-live-on.off .ex-dot {
  background: var(--pickle-amber);
  animation: none;
}

/* The beat: the bar's bottom edge under the Mini-block cell, lit on each real
   read. Positioned from the cell rather than the bar so it sits under the one
   figure the read produced. The item is centred in the bar, so half the bar's
   height down from the item's middle is the bar's edge; the 2px step back
   keeps the 2px line inside the bar's box, because the bar is a scroll
   container and a line hanging half a pixel out of it is a scrollbar. */
.arc-beat {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(50% - var(--pickle-bar-h) / 2 + 2px);
  height: 2px;
  background: var(--pickle-mint);
  opacity: 0;
  transform-origin: 0 50%;
  pointer-events: none;
}

/* Reduced motion: a still lit edge while the chain answers, dark otherwise. A
   dead chain never has a lit edge beside it. */
body[data-app="minigame"] .ex-livebar.live .arc-beat { opacity: .6; }

/* components.css gives .ex-out and .ex-banner a success colour and an error
   colour and nothing in between, so every page that had something to say which
   was neither rendered it in mint. A warning is not a confirmation, and on this
   site that distinction is the product: "no receipt came back" and "you died"
   were both reading as good news. Amber, the same amber the live bar already
   uses for a chain it cannot reach. */
body[data-app="minigame"] .ex-out.warn,
body[data-app="minigame"] .ex-banner.warn {
  color: var(--pickle-amber);
  border-color: var(--pickle-amber-line);
}

/* ======================================================================= nav
 * Scoped to this origin; shared-ui is served to ten sites. Measured at 375 the
 * estate's `.ex-nav.stack` wrapped to three rows (217px) with the tab row
 * clipped mid-word, and at 768 a signed-in account button pushed the burger to
 * a second row and the stage down 44px. One row is the rule: the rail shrinks
 * and scrolls instead of wrapping, its tabs tighten where the bar is narrow,
 * and under 640px the rail goes entirely, because the burger and .ex-mobmenu
 * already carry the same four tabs. Every control keeps its 44px. */
@media (max-width: 1219px) {
  body[data-app="minigame"] .ex-nav {
    flex-wrap: nowrap;
    gap: 0 var(--pickle-space-4);
  }

  /* The brand never shrinks; the rail does. */
  body[data-app="minigame"] .ex-nav .ex-brand { flex: 0 0 auto; }
}

@media (max-width: 1023px) {
  body[data-app="minigame"] .ex-nav .ex-brand span { display: none; }

  body[data-app="minigame"] .ex-nav .ex-subnav a {
    padding-inline: var(--pickle-space-3);
    font-size: var(--pickle-text-sm);
  }
}

@media (max-width: 639px) {
  body[data-app="minigame"] .ex-nav .ex-subnav { display: none; }

  /* An account address must never wrap the row. Narrower padding first, so a
     shortened address still fits whole; the cap and the ellipsis are for a
     longer label wallet.js may write. No view() timeline sits in a button, so
     overflow: hidden is safe here. */
  body[data-app="minigame"] .ex-nav .ex-wallet .ex-btn {
    max-width: 8.5rem;
    padding: 0 var(--pickle-space-3);
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* ===================================================================== house
 * The hall's first screen: the live arena on the big screen beside the
 * headline. Full-bleed between the live bar and main, edge to edge. */
.arc-house {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  min-height: var(--arc-house-h);
  background: var(--pickle-bg);
  border-bottom: 1px solid var(--pickle-line);
  /* Clipped sideways so nothing in it can widen the page; open downward so
     the pool of light below (the ::after) can fall on the hall floor. `clip`,
     never `hidden`: hidden would make a scroll container. */
  overflow: clip visible;
}

/* The headline sits on page ground, never over the picture; at 1024px and
   above it is the left column and the picture melts toward it. */
.arc-house-head {
  align-self: center;
  padding: var(--pickle-space-8) var(--pickle-space-6) var(--pickle-space-7) var(--arc-inset);
  min-width: 0;
}

.arc-house-head .ex-h { font-size: var(--pickle-text-display); max-width: 16ch; }
.arc-house-head .ex-lede { margin-bottom: 0; }

/* The screen: a dark glass with graph paper and a pool of the cabinet's light
   at its foot. With no script at all, this is what shows; once the view draws,
   the canvas paints its own floor over it. */
.arc-house-screen {
  position: relative;
  min-height: 0;
  background:
    radial-gradient(ellipse at 50% 100%, var(--arc-light-glow), transparent 60%),
    repeating-linear-gradient(0deg, var(--arc-grid) 0 1px, transparent 1px 100px),
    repeating-linear-gradient(90deg, var(--arc-grid) 0 1px, transparent 1px 100px),
    var(--arc-glass);
}

/* The picture melts toward the text: painted OVER the canvas, under the line. */
.arc-house-screen::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(90deg, var(--pickle-bg) 0, transparent 12rem);
}

/* The element's size is the stylesheet's; the view only writes the drawing
   buffer, so no device pixel ratio can make it wider than its column. */
.arc-house-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* The one place the room is named: asking, unreachable, live, or a demo. */
.arc-house-live {
  position: absolute;
  right: var(--arc-inset);
  bottom: var(--pickle-space-4);
  z-index: 2;
  margin: 0;
  font-size: var(--pickle-text-xs);
  color: var(--pickle-subtle);
}

.arc-house-live.down { color: var(--pickle-amber); }

/* The pool of light on the hall floor under the screen. It paints below the
   house's hairline, over main, which has no background. */
.arc-house::after {
  content: "";
  position: absolute;
  left: 30%;
  right: 0;
  bottom: -3.5rem;
  height: 3.5rem;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at 70% 0%, var(--arc-light-glow), transparent 70%);
}

@media (max-width: 1023px) {
  /* The picture is a screen ABOVE the head, so no text ever sits over it and
     the screen turning on is the first thing seen. */
  .arc-house { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .arc-house-screen { order: -1; aspect-ratio: 16 / 10; width: 100%; max-width: 100%; }
  .arc-house-screen::before { display: none; }
  .arc-house-head { padding: var(--pickle-space-6) var(--pickle-gutter) var(--pickle-space-6); }
  .arc-house-live { right: var(--pickle-gutter); }
}

@media (max-width: 639px) {
  .arc-house-screen { aspect-ratio: 4 / 3; }
}

/* =================================================================== tickets
 * Three tickets under the house: a strip of paper with a column of each
 * cabinet's light behind a dashed perforation. The grid is the estate's
 * 1px-gap frame, so the cells never animate; their contents do. */
.arc-tickets {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--pickle-line);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  /* clip, never hidden: `overflow: hidden` makes a scroll container and every
     view() timeline below it freezes at its end state. */
  overflow: clip;
  margin-top: var(--pickle-space-6);
}

.arc-ticket {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  background: var(--pickle-surface-1);
  min-height: 15rem;
}

/* The stub is pure light: no text, no number. */
.arc-ticket-stub {
  position: relative;
  border-right: 1px dashed var(--pickle-line);
  background: radial-gradient(120% 60% at 50% 100%, var(--arc-light-glow), transparent 75%);
}

/* The stub's own tube, 2px along its top edge. */
.arc-ticket-stub::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: var(--arc-light-tube);
}

.arc-ticket-body {
  display: flex;
  flex-direction: column;
  gap: var(--pickle-space-3);
  padding: var(--pickle-space-5) var(--pickle-space-6);
  min-width: 0;
}

.arc-ticket-name {
  margin: 0;
  font-family: var(--pickle-font-display);
  font-size: var(--pickle-text-xl);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: var(--pickle-leading-display);
  color: var(--pickle-text);
}

/* The number rides inside the name, small mono caps; no kicker repeats it. */
.arc-ticket-name .n {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xs);
  font-weight: 400;
  margin-right: var(--pickle-space-3);
  vertical-align: .35em;
  letter-spacing: var(--pickle-tracking-caps);
}

.arc-cabinet-line {
  color: var(--pickle-muted);
  font-size: var(--pickle-text-sm);
  flex: 1;
  margin: 0;
}

.arc-ticket .ex-btn,
.arc-ticket .ex-pill { align-self: flex-start; }

/* Being built: dimmer words and a dimmer light. A still light says closed; an
   attract loop would flirt with implying the game can be played. */
.arc-soon .arc-cabinet-line { color: var(--pickle-subtle); }
.arc-soon .arc-ticket-stub { opacity: .7; }

/* The ticket's live figure line, three answers: asking, unreachable, or the
   count. Never "0" for "no answer". */
.arc-cabinet-live {
  margin: 0;
  font-size: var(--pickle-text-xs);
  color: var(--pickle-text);
  display: inline-flex;
  align-items: center;
  gap: var(--pickle-space-2);
}

.arc-cabinet-live .ex-dot { margin: 0; background: currentColor; }
.arc-cabinet-live.asking { color: var(--pickle-muted); }
.arc-cabinet-live.asking .ex-dot { background: rgb(255 255 255 / 40%); animation: none; }
.arc-cabinet-live.down { color: var(--pickle-amber); }
.arc-cabinet-live.down .ex-dot { background: var(--pickle-amber); animation: none; }
.arc-cabinet-live.live .ex-dot { background: var(--pickle-mint); }

/* Twenty-four seats, one rect each, the taken ones in the cabinet's light. */
.arc-seats { display: block; width: 100%; height: 8px; }
.arc-seat { fill: var(--pickle-line); }
.arc-seat-on { fill: var(--arc-light); }

/* The 404's one unlit ticket: no light, no tube, dimmer words. It stands
   alone rather than in the strip, so it carries its own frame. */
.arc-ticket.arc-dark {
  --arc-light-glow: transparent;
  --arc-light-tube: transparent;
  max-width: 32rem;
  margin-bottom: var(--pickle-space-6);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  /* The 15rem floor is there to keep three cells in the strip the same height.
     Alone, it is 10rem of empty box under two lines, which reads as a ticket
     whose contents failed to load rather than as one that was never printed. */
  min-height: 0;
}

.arc-dark .arc-ticket-name,
.arc-dark .arc-cabinet-line { color: var(--pickle-subtle); }

@media (max-width: 820px) {
  .arc-tickets { grid-template-columns: minmax(0, 1fr); }
  .arc-ticket { min-height: 0; }
}

/* ====================================================================== door
 * The wallet's one object: the two figures under the tube, the coin slot with
 * Deposit and Withdraw either side of the amount, and the device's key strip. */
.arc-door {
  position: relative;
  isolation: isolate;
  background: var(--pickle-surface-1);
  border: 1px solid var(--pickle-line);
  border-radius: var(--pickle-radius);
  overflow: clip;
  margin-bottom: var(--pickle-space-5);
}

.arc-door-row {
  padding: var(--pickle-space-5);
  border-top: 1px solid var(--pickle-line);
}

/* The tube's light falls off downward through the first row. */
.arc-door-row:first-of-type {
  border-top: 0;
  background: linear-gradient(180deg, var(--arc-light-glow) 0%, transparent 70%);
}

.arc-door-figs {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: var(--pickle-space-5);
}

.arc-fig {
  display: flex;
  flex-direction: column;
  gap: var(--pickle-space-2);
  min-width: 0;
}

/* The sanctioned .62rem mono caps label, as .ex-stat span sets it. */
.arc-fig span {
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.arc-fig b {
  font-family: var(--pickle-font-mono);
  font-size: var(--pickle-text-xl);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--pickle-text);
  overflow-wrap: anywhere;
}

/* The vault is the page's one display-size figure. */
.arc-fig.big b { font-size: var(--arc-read); }

.arc-slot { background: var(--pickle-surface-2); }

.arc-slot label {
  display: block;
  margin-bottom: var(--pickle-space-3);
  color: var(--pickle-subtle);
  font-family: var(--pickle-font-mono);
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}

/* Deposit, the amount, Withdraw: the buttons stretch to the coin's height. */
.arc-slot-in {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--pickle-space-3);
  align-items: stretch;
}

.arc-slot-in input {
  min-width: 0;
  width: 100%;
  text-align: center;
  font-family: var(--pickle-font-mono);
  font-size: var(--arc-coin);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--pickle-text);
  background: var(--arc-glass);
  border: 1px solid var(--pickle-surface-4);
  border-radius: var(--pickle-radius);
  padding: var(--pickle-space-2) var(--pickle-space-3);
}

.arc-slot-in input:focus { outline: 0; border-color: var(--pickle-mint-line); }
.arc-slot-in input[aria-invalid="true"] { border-color: var(--pickle-rose-line); }
.arc-slot .ex-out { margin-top: var(--pickle-space-3); }

/* The key strip: the device's full address, its state in a word, its gas. */
.arc-key {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-4);
  align-items: center;
  justify-content: space-between;
}

.arc-key-id {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-2) var(--pickle-space-3);
  align-items: baseline;
  font-size: var(--pickle-text-sm);
  color: var(--pickle-text);
  min-width: 0;
}

.arc-key-id span {
  color: var(--pickle-subtle);
  font-size: .62rem;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.arc-key-id b { font-weight: 500; overflow-wrap: anywhere; }
.arc-key-id em { font-style: normal; color: var(--pickle-muted); font-size: var(--pickle-text-xs); }

/* Another device holds the registration: rose, because this one cannot play. */
.arc-key-state.bad { color: var(--pickle-rose); }

/* Nearly out of gas money: amber, the warning before a move fails. */
.arc-key-gas.low { color: var(--pickle-amber); }

/* The buttons wrap rather than clip: .ex-btn is nowrap, and at 375 a flexed
   button used to cut "Deposit and register this device" to its middle. */
.arc-key-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pickle-space-3);
}

@media (max-width: 820px) {
  /* The door stacks: figures one under the other, the slot as amount then
     Deposit then Withdraw, the key strip as words then buttons. */
  .arc-door-figs { grid-template-columns: minmax(0, 1fr); }
  .arc-slot-in { grid-template-columns: minmax(0, 1fr); }
  .arc-slot-in input { order: -1; }
  .arc-slot-in .ex-btn { white-space: normal; }
  .arc-key { flex-direction: column; align-items: stretch; }
}

/* ====================================================================== fair
 * Typographic treatment only: tighter sections, a measure for the prose, and
 * the one figure, a hairline mint where the chain proves and unlit where the
 * server computes. */
body[data-app="minigame"] .ex-section p { max-width: 62ch; }

/* base.css sets `p { margin: 0 }` and leaves the gap to whichever component
   holds the prose, and this page holds it in bare `.ex-section`s: measured,
   its paragraphs ran together into one block with no break between the
   arguments they make. The gap is the paragraph, so it is set here. */
body[data-app="minigame"] .ex-section p + p { margin-top: var(--pickle-space-4); }

/* `.ex-h3-label` is components.css's inline-flex wrapper for a panel heading,
   not a size, so an h2 wearing it takes base.css's app-safe step: --pickle-text-3xl,
   the same size as the page's own headline. Four of those down one editorial
   page read as four headlines rather than as sections of one argument. The
   ticket name's step (xl at 600) is this site's one subheading size. */
body[data-app="minigame"] .ex-section > .ex-h3-label {
  display: block;
  margin-bottom: var(--pickle-space-4);
  font-size: var(--pickle-text-xl);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: var(--pickle-leading-display);
}

/* Mint for the half of the page that is proved; the other three headings stay
   as they are, because a page where everything is highlighted highlights
   nothing. */
body[data-app="minigame"] .ex-section:first-of-type .ex-h3-label { color: var(--pickle-accent-text); }

/* No margin of its own: the two sections' padding frames it evenly, so the
   line is a boundary and not a footnote to the section above. */
.arc-line {
  border: 0;
  height: 1px;
  margin: 0;
  background: linear-gradient(90deg, var(--pickle-mint) 0 50%, var(--pickle-line) 50% 100%);
}

/* ==================================================================== motion
 * Same contract as shared-ui/motion.css: every rule with a duration lives
 * under the reduced-motion gate; scroll-driven rules also under @supports with
 * longhands only. Under reduce, base.css zeroes every duration and everything
 * below sits at its end state. Nothing here loops to a clock; the live bar's
 * beat is fired by a real read. */
@media (prefers-reduced-motion: no-preference) {
  /* The beat is dark until a read lands, then draws and fades. */
  body[data-app="minigame"] .ex-livebar.live .arc-beat { opacity: 0; }
  .arc-beat.on { animation: arc-beat 700ms var(--pickle-ease) both; }

  /* The house head sits outside .ex-wrap, so the estate's four load rules are
     restated for it: eyebrow, headline, standfirst, then the accent lands. */
  .arc-house-head .ex-kicker,
  .arc-house-head .ex-h,
  .arc-house-head .ex-lede { animation: ex-in 620ms var(--pickle-ease) both; }
  .arc-house-head .ex-kicker { animation-delay: 40ms; }
  .arc-house-head .ex-h { animation-delay: 130ms; }
  .arc-house-head .ex-lede { animation-delay: 220ms; }
  .arc-house-head .ex-h .accent { animation: ex-in 520ms var(--pickle-ease) 320ms both; }

  .arc-house-head .ex-kicker::before {
    animation: arc-rule 420ms var(--pickle-ease) 40ms both;
    transform-origin: 0 50%;
  }

  /* The hall's one orchestrated moment: the tube strikes at 320 ms, the
     screen turns on at 620 ms, the live line and the pool fade in after. */
  .arc-house .arc-tube { animation: arc-strike 480ms steps(1, end) 320ms both; }

  .arc-house-screen {
    animation: arc-screen-on 260ms var(--pickle-ease) 620ms both;
    transform-origin: 50% 50%;
  }

  .arc-house-live { animation: ex-in-sm 380ms var(--pickle-ease) 900ms both; }
  .arc-house::after { animation: ex-in 900ms var(--pickle-ease) 700ms both; }

  /* The wallet: the door's tube strikes, then the door rises as one block. */
  .arc-door .arc-tube { animation: arc-strike 480ms steps(1, end) 320ms both; }
  .arc-door { animation: ex-in-sm 480ms var(--pickle-ease) 520ms both; }

  /* The 404's dark ticket rises with the button. */
  .arc-dark { animation: ex-in-sm 420ms var(--pickle-ease) 320ms both; }

  @supports (animation-timeline: view()) {
    /* The tickets on scroll: the frame draws itself, then each ticket's
       CONTENTS rise, finishing later across the strip. The cell itself is
       never animated: the 1px-gap grid would show its ground through a faded
       cell. Longhands, because the shorthand resets animation-timeline. */
    .arc-tickets {
      animation-name: ex-frame;
      animation-duration: auto;
      animation-fill-mode: both;
      animation-timeline: view(block);
      animation-range: entry 0% entry 40%;
    }

    .arc-tickets .arc-ticket > * {
      animation-name: ex-in-sm;
      animation-duration: auto;
      animation-fill-mode: both;
      animation-timeline: view(block);
      animation-range: entry 8% entry 58%;
    }

    .arc-tickets > :nth-child(2) > * { animation-range: entry 8% entry 68%; }
    .arc-tickets > :nth-child(3) > * { animation-range: entry 8% entry 78%; }
  }
}
