/* The premium client (docs/client/DESIGN.md), in the art pass's look
   (docs/client/ART-PASS.md). Colours are tokens, so screens never name one.
   Mobile first: phone portrait is the base, wider screens add room. */

/* The pixel font, for short labels only: titles, names, buttons, banners.
   Anything read as a sentence, and any label too small for pixel type, stays
   in the system font. m5x7 by Daniel Linssen, public domain (CC0;
   fonts/m5x7-LICENCE.txt). It's drawn on a 7px grid: 32px is 2x, the HUD's
   scale, and 48px is 3x; other sizes would blur its pixels. Mixed case reads
   best; only the big banners are in capitals. */
@font-face {
  font-family: 'm5x7';
  src: url('fonts/m5x7.ttf') format('truetype');
  font-display: swap;
}

/* The colours follow the window skins (art/ui.json): navy windows, a
   blue-silver rim for normal and gold for attention. --gold and --dim are
   also the recipe's colours, and a test holds the two equal. */
:root {
  --ground: #0a0d18;
  --panel: #0e1a3c;
  --panel-2: #0a1430;
  --line: #24345e;
  --text: #eef2f6;
  --muted: #a3b0c8;
  --rim: #6fa5f6;
  --gold: #edc329;
  --gold-deep: #6b4c00;
  --on-gold: #11141d;
  --dim: #5a6478;
  --panel-attention: #2a2210;
  --win: #5fc46a;
  --loss: #c25a5a;
  --font-pixel: 'm5x7', ui-monospace, monospace;
  /* Pixel type's soft drop shadow: it thickens the strokes and lifts them off the window. */
  --pixel-shadow: 2px 2px 0 rgba(0, 0, 0, .55);
  --radius: 12px;
  --gutter: 16px;
  --tap: 44px;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--ground);
  color: var(--text);
  font: 16px/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;
  -webkit-tap-highlight-color: transparent;
}
a { color: var(--gold); }
:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }

.skip { position: absolute; left: -9999px; top: 8px; z-index: 10; background: var(--panel); padding: 8px 12px; border-radius: 8px; }
.skip:focus { left: 8px; }

.app {
  min-height: 100%;
  max-width: 960px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.loading { margin: auto; color: var(--muted); }
.content { flex: 1; padding: 8px var(--gutter) var(--gutter); outline: none; }

/* The frame: back and title at the top, one primary action in the thumb zone. */
.bar { display: flex; align-items: center; gap: 8px; padding: 12px var(--gutter) 4px; }
.bar h1 { margin: 0; font: 400 32px/1 var(--font-pixel); text-shadow: var(--pixel-shadow); }
.thumb-zone { position: sticky; bottom: 0; padding: 12px var(--gutter) calc(16px + env(safe-area-inset-bottom)); background: linear-gradient(transparent, var(--ground) 30%); }

.btn {
  min-height: var(--tap);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 0 16px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); color: var(--text);
  font: inherit; text-decoration: none; cursor: pointer;
}
.icon-btn { width: var(--tap); padding: 0; }
.primary { background: var(--gold); color: var(--on-gold); border: 0; font-weight: 700; }
.primary:focus-visible { outline-color: var(--text); }
.divider { height: 2px; margin: 8px 0; background: var(--line); }
.big { width: 100%; min-height: 56px; font: 400 32px/1 var(--font-pixel); border-radius: 14px; }
.icon { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.muted { color: var(--muted); }
.accent { color: var(--gold); }
.stack { display: flex; flex-direction: column; gap: 12px; }
.row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.placeholder { border: 2px dashed var(--dim); color: var(--muted); border-radius: var(--radius); padding: 16px; text-align: center; }
.placeholder.big { min-height: 240px; display: grid; place-items: center; }

/* Landing: full-bleed splash, profile chip top left, Play in the thumb zone. */
[data-screen="landing"] .content { position: relative; display: flex; flex-direction: column; padding-top: 16px; }
.landing { flex: 1; display: flex; flex-direction: column; gap: 16px; }
/* The god stands in the sacred grove: the scene and the sprite at one scale
   (--k), so the god is always the scene's own size, with the shrine behind.
   The scale is the smallest whole multiple that still fills the screen: 3x on
   a phone (4x only on a large screen, 2x on a landscape phone), since bigger
   pixels show less of the room and read blocky rather than crisp. On a screen
   taller than the scene, the scene moves down (--top, at most 96px) so the
   shrine clears the name, and the top fades into the ground. The god is placed
   in the scene's own pixels (--stand), not the screen's, so it stays on the
   path before the shrine at any scale. Dark at the top for the name and at
   the bottom for the buttons. Without the scene, the plain ground. */
.splash { --k: 3; --scene: url('../skin/scenes/sacred-grove-handheld.png'); --sw: 256px; --sh: 288px; --top: clamp(0px, calc(100dvh - var(--sh) * var(--k)), 96px); position: fixed; inset: 0; z-index: -1; background: var(--ground) var(--scene) center var(--top) / calc(var(--sw) * var(--k)) calc(var(--sh) * var(--k)) no-repeat; image-rendering: pixelated; }
@media (min-width: 720px) and (min-height: 1000px) { .splash { --k: 4; } }
@media (max-height: 600px) { .splash { --k: 2; } }
/* Landscape: the grove's wide framing, whose shrine and path sit at the same
   rows as the portrait one's (so --stand holds), at the smallest whole scale
   that spans the screen's width: the portrait framing left the sides bare. */
@media (orientation: landscape) {
  .splash { --scene: url('../skin/scenes/sacred-grove-arena.png'); --sw: 576px; --sh: 288px; --k: 2; }
}
@media (orientation: landscape) and (min-width: 1153px) { .splash { --k: 3; } }
@media (orientation: landscape) and (min-width: 1729px) { .splash { --k: 4; } }
@media (orientation: landscape) and (min-width: 2305px) { .splash { --k: 5; } }
.splash::after { content: ""; position: absolute; inset: 0; background: linear-gradient(var(--ground) var(--top), rgba(10, 13, 24, .55) calc(var(--top) + 64px), rgba(10, 13, 24, 0) 30%, rgba(10, 13, 24, 0) 62%, rgba(10, 13, 24, .9) 84%); }
/* --stand: the sprite cell's top in scene pixels, which puts the feet on the path just below the shrine. */
.splash-hero { --stand: 105; position: absolute; left: 50%; top: calc(var(--top) + var(--stand) * var(--k) * 1px); z-index: 1; display: block; transform: translateX(-50%); font-size: 0; line-height: 0; }
/* Time Elements cells leave 17px below the feet: the shadow sits under them, not under the cell. */
.splash-hero::after { content: ""; position: absolute; left: 50%; bottom: calc(var(--k) * 15px); z-index: -1; width: calc(var(--k) * 22px); height: calc(var(--k) * 4px); margin-left: calc(var(--k) * -11px); border-radius: 50%; background: rgba(0, 0, 0, .45); }
.splash-hero .splash-sprite:not(.sheet-sprite) { font-size: min(48vw, 220px); line-height: 1; }
.chip { display: inline-flex; align-items: center; gap: 10px; align-self: flex-start; min-height: var(--tap); padding: 4px 14px 4px 4px; border: 1px solid var(--line); border-radius: 999px; background: rgba(17, 20, 29, .85); color: var(--text); font: inherit; cursor: pointer; text-align: left; }
.chip small { display: block; color: var(--muted); font-size: 12px; }
.avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--line); display: grid; place-items: center; }
/* The name and tagline over the scene: a soft dark glow behind them, fading
   into the room, and a dark halo on the letters, so they read over the wall
   without a box. */
.brand { position: relative; isolation: isolate; text-align: center; margin-top: 32px; padding: 20px 0 24px; }
.brand::before { content: ""; position: absolute; inset: -44px 0; z-index: -1; background: radial-gradient(closest-side, rgba(10, 13, 24, .95), rgba(10, 13, 24, .8) 45%, rgba(10, 13, 24, .4) 75%, rgba(10, 13, 24, 0)); pointer-events: none; }
.brand h1 { margin: 0; font: 400 48px/1 var(--font-pixel); color: var(--gold); text-transform: uppercase; text-shadow: 0 3px 0 var(--gold-deep), 0 6px 0 #000, 0 0 18px rgba(0, 0, 0, .9); }
.brand p { margin: 8px auto 0; max-width: 34ch; font-size: 15px; color: var(--text); text-shadow: 0 1px 0 #000, 0 0 6px #000, 0 0 12px rgba(0, 0, 0, .8); }
.landing .splash-name { margin: auto 0 0; text-align: center; font-size: 14px; color: var(--muted); text-shadow: 0 1px 2px #000; }
.splash-name strong { font: 400 32px/1 var(--font-pixel); color: var(--text); text-shadow: var(--pixel-shadow); }
.landing .splash-name + .quick { margin-top: 12px; }
.quick { margin-top: auto; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.tile { min-height: 64px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; border: 1px solid var(--line); border-radius: var(--radius); background: rgba(35, 38, 49, .9); color: var(--text); text-decoration: none; font-size: 14px; }

/* Mode select. */
.card { display: flex; gap: 14px; align-items: center; width: 100%; padding: 16px; border: 2px solid var(--line); border-radius: 14px; background: var(--panel); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.card[aria-checked="true"] { border-color: var(--gold); background: var(--panel-attention); }
.card-text { display: flex; flex-direction: column; gap: 4px; }
.card-text strong { font: 400 32px/1 var(--font-pixel); text-shadow: var(--pixel-shadow); }
.card-text span { font-size: 14px; }
.emblem { width: 56px; height: 56px; flex: none; display: grid; place-items: center; border-radius: 12px; background: rgba(0, 0, 0, .35); font-size: 30px; line-height: 1; }

/* Gods gallery and a god's page. */
.count { margin: 0 0 12px; }
.gallery { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.god-card { min-height: 180px; display: flex; flex-direction: column; justify-content: flex-end; gap: 2px; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); color: var(--text); text-decoration: none; }
.god-card .portrait { flex: 1; display: grid; place-items: center; font-size: 48px; }
.god-card .muted { font-size: 13px; }
/* A god's page (ART-PASS.md step 5): a window onto the sacred grove (its wide
   framing, 2304px across at 4x, so it spans any page) with the
   god on the path, scene and sprite at one scale (--k), the name over the
   bottom of it; then a row per stat, its icon, a meter against the roster's
   highest, and the number. */
.hero-banner { --k: 4; position: relative; height: calc(56px * var(--k)); display: grid; place-items: center; overflow: hidden; border: 2px solid var(--line); border-radius: var(--radius); background: var(--panel) url('../skin/scenes/sacred-grove-arena.png') center 52% / calc(576px * var(--k)) calc(288px * var(--k)) no-repeat; image-rendering: pixelated; }
@media (max-height: 760px) { .hero-banner { --k: 3; } }
.hero-banner::after { content: ""; position: absolute; inset: 0; background: linear-gradient(rgba(10, 13, 24, 0) 45%, rgba(10, 13, 24, .9)); pointer-events: none; }
.hero-portrait { position: relative; z-index: 1; margin-bottom: 36px; font-size: 64px; line-height: 1; }
.hero-portrait .sheet-sprite { --s: var(--k); }
.hero-title { position: absolute; left: 16px; right: 16px; bottom: 12px; z-index: 2; }
.hero-title h2 { margin: 0; font: 400 48px/1 var(--font-pixel); text-shadow: 3px 3px 0 #000; }
.hero-title p { margin: 2px 0 0; text-shadow: 0 1px 2px #000; }
.stats { margin: 0; display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); }
.stat { display: grid; grid-template-columns: 82px minmax(0, 1fr); align-items: center; gap: 10px; }
.stat dt { display: flex; align-items: center; gap: 8px; font: 400 32px/1 var(--font-pixel); color: var(--muted); text-shadow: var(--pixel-shadow); }
.stat dd { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) 48px; align-items: center; gap: 10px; }
.stat .bar-track { display: block; height: 10px; }
.stat .bar-fill { display: block; height: 100%; }
.stat-num { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.bar-track.atk .bar-fill { background: var(--loss); }
.bar-track.def .bar-fill { background: var(--gold); }
.bar-track.spd .bar-fill { background: #7f9cff; }
.ability-type { display: inline-block; margin-right: 8px; padding: 2px 6px; font: 700 11px/1.2 system-ui, -apple-system, 'Segoe UI', sans-serif; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); background: rgba(0, 0, 0, .35); vertical-align: 2px; }
.ability.ultimate .ability-type { color: var(--gold); }
.ability-cost { margin-left: 8px; font-size: 13px; font-weight: 400; color: var(--muted); white-space: nowrap; }
.ability, .lore { padding: 12px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); }
.ability h3, .lore h3 { margin: 0 0 4px; font-size: 16px; }
.ability p, .lore p { margin: 0; }

/* Settings: plain radio groups, drawn as segmented controls. */
.group { margin: 0; padding: 12px; border: 1px solid #2a2d37; border-radius: var(--radius); background: var(--panel-2); }
.group legend, .legend { padding: 0; margin: 0 0 8px; font: 400 32px/1 var(--font-pixel); color: var(--text); text-shadow: var(--pixel-shadow); }
.sub-setting { margin: 14px 0 0; padding: 0; border: 0; min-width: 0; }
.group .sub-setting > legend { margin-bottom: 6px; font-family: inherit; font-size: 16px; font-weight: 700; line-height: 1.2; text-shadow: none; }
.segmented { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px; padding: 4px; border-radius: 10px; background: var(--panel); }
.segmented label { position: relative; }
.segmented input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.segmented span { min-height: 40px; display: grid; place-items: center; border-radius: 8px; color: #c9ccd6; font-size: 14px; }
.segmented input:checked + span { background: var(--text); color: var(--ground); font-weight: 700; }
.segmented input:focus-visible + span { outline: 3px solid var(--gold); outline-offset: 1px; }
.help { margin: 8px 0 0; font-size: 13px; }

.toast { position: fixed; left: 50%; bottom: calc(96px + env(safe-area-inset-bottom)); transform: translateX(-50%); padding: 10px 16px; border-radius: 999px; background: var(--text); color: var(--ground); font-weight: 600; }

/* Wider screens: more room, same game. */
@media (min-width: 720px) {
  .gallery { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .thumb-zone { display: flex; justify-content: flex-end; }
  .thumb-zone .big { width: 280px; }
}

/* Motion: calm unless the player chose full and the device doesn't ask for less. */
[data-motion="full"] .btn, [data-motion="full"] .card, [data-motion="full"] .tile, [data-motion="full"] .god-card { transition: transform .12s ease, border-color .12s ease; }
[data-motion="full"] .btn:active, [data-motion="full"] .card:active, [data-motion="full"] .tile:active { transform: scale(.98); }
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* Only for screen readers: the text a picture stands for. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* The battle, handheld view (#38): top to bottom, timeline, foes, your
   champion and allies, SP, commands, then the battle line. Sized for a
   phone in portrait first; nothing scrolls sideways at 400px. */
[data-layout="battle"] .content { padding: 0; display: flex; }
/* overflow-x: clip: a sprite's whole cell may reach past the screen's edge
   (only its crop is laid out), and must not make the page scroll sideways. */
.battle { position: relative; flex: 1; min-width: 0; display: flex; overflow-x: clip; min-height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom)); }
/* The installed app: the battle's backdrop reaches up under the status bar
   (the box starts at the screen's top, its content still below the bar),
   rather than leaving the bar a band of plain ground. */
@media (display-mode: standalone), (display-mode: fullscreen) {
  .battle { margin-top: calc(-1 * env(safe-area-inset-top)); padding-top: env(safe-area-inset-top); min-height: calc(100dvh - env(safe-area-inset-bottom)); }
}
/* .app already keeps the page out of the safe areas, so the battle fills the
   screen between them, and counting them again here made it scroll. */
.battle-stage { flex: 1; display: flex; flex-direction: column; gap: 10px; padding: 8px 12px 12px; min-width: 0; }
.battle-overlay { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }

.battle-top { display: flex; align-items: center; gap: 8px; }
.timeline { flex: 1; min-width: 0; display: flex; gap: 4px; margin: 0; padding: 0; list-style: none; overflow: hidden; }
.timeline li { flex: none; width: 44px; height: 44px; display: grid; place-items: center; overflow: hidden; border-radius: 8px; background: var(--panel); border: 2px solid transparent; font-size: 22px; }
.timeline li.mine { border-color: var(--rim); }
.timeline li.theirs { border-color: var(--loss); }
.timeline li.now { width: 52px; height: 52px; font-size: 26px; border-color: var(--gold); }
/* A unit's face in the turn order (#70): a square of its sheet at --k, 2 like
   the rest of the HUD, 1 on a landscape phone where the battle must fit. */
.face { --k: 2; display: block; width: calc(var(--face-size) * var(--k) * 1px); height: calc(var(--face-size) * var(--k) * 1px); background: var(--face-src) no-repeat; background-size: calc(var(--sheet-w) * var(--k) * 1px) calc(var(--sheet-h) * var(--k) * 1px); background-position: calc(var(--face-x) * var(--k) * -1px) calc(var(--face-y) * var(--k) * -1px); image-rendering: pixelated; }
@media (max-height: 520px) {
  .timeline li { width: 34px; height: 34px; font-size: 18px; }
  .timeline li.now { width: 40px; height: 40px; font-size: 20px; }
  .face { --k: 1; }
}
.wave-label { font-size: 13px; color: var(--muted); white-space: nowrap; }

.foes { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.allies { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 6px; }
.party { display: flex; flex-direction: column; gap: 8px; }
/* Your team follows the enemies straight down the screen; any spare height
   goes above the SP and the commands, which keep to the thumb zone. */
.party + .controls > .sp, :is([data-thumb="right"], [data-thumb="left"]) .party + .controls { margin-top: auto; }
:is([data-thumb="right"], [data-thumb="left"]) .party + .controls > .sp { margin-top: 0; }
/* On the ground every second fighter steps down 14px (.ground-side): room for it above the arc's top button. */
:is([data-thumb="right"], [data-thumb="left"]) .ground-bottom + .controls { margin-top: 14px; }
/* A shorter phone (most, once the safe areas are taken): the handheld view
   tightens so the whole battle fits without scrolling, and drops the
   standing long-press hint (a long-pressed command's own still shows). */
@media (max-height: 800px) {
  .battle-stage:not(.arena) { gap: 8px; padding-top: 6px; }
  .battle-stage:not(.arena) .hint.muted { display: none; }
  .battle-stage:not(.arena) .commands { min-height: 96px; }
}
/* The same for the side-on camera held upright on a shorter phone. */
@media (orientation: portrait) and (max-height: 800px) {
  .battle-stage.arena { gap: 8px; }
  .battle-stage.arena .hint.muted { display: none; }
}
/* Held upright, the side-on teams have half a phone's width each: a smaller
   step back and a narrower gap keep the far fighters on the screen. */
@media (orientation: portrait) {
  .arena-field:not(.lines) { gap: 12px; }
  .arena-side.mine > :nth-child(even) { transform: translateX(-8%); }
  .arena-side.theirs > :nth-child(even) { transform: translateX(8%); }
}
/* The handheld view with the Fighters setting on the ground: each side a row
   of fighters (styled with the arena's, below) across the room, theirs facing
   you and yours from behind nearer the commands. Every other one stands a
   step lower, so a row reads as people standing rather than a table. */
.ground-side { --s: 2; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-items: end; justify-items: center; gap: 4px; padding-bottom: 14px; }
.ground-side > :nth-child(even) { transform: translateY(14px); }
@media (min-width: 400px) and (min-height: 800px) { .ground-side { --s: 3; } }
/* The handheld view's two lines stand close, face to face, just above the
   commands, whichever team the camera puts where; the spare height goes
   above them, to the grove's trees and shrine. */
.ground-top { margin-top: auto; }
.ground-bottom { margin-top: 12px; }

.unit, .lead { display: flex; align-items: center; gap: 8px; min-width: 0; padding: 6px 8px; border: 2px solid var(--line); border-radius: 10px; background: var(--panel); color: var(--text); font: inherit; text-align: left; }
.unit .sprite { font-size: 28px; line-height: 1; flex: none; }
.unit-info, .lead-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.unit-name { display: flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.unit.acting, .lead.acting { border-color: var(--gold); }
.unit.fallen, .lead.fallen { opacity: .4; }
.pickable { cursor: pointer; border-color: #7fc4ff; box-shadow: 0 0 0 2px rgba(127, 196, 255, .35); }
.unit.chosen { border-style: dashed; }
.badge { margin-left: auto; padding: 0 6px; border-radius: 999px; background: var(--gold); color: var(--on-gold); font-size: 11px; }
.weak { display: inline-flex; gap: 1px; font-size: 12px; }

.lead { padding: 10px; }
.lead .sprite.lg { font-size: 56px; line-height: 1; flex: none; }
.lead-info strong { font-size: 17px; }
.nums { font-size: 13px; color: var(--muted); }

.bar-track { height: 7px; border-radius: 4px; background: #11131a; overflow: hidden; }
.bar-fill { height: 100%; background: #5fc46a; }
.bar-track.tough .bar-fill { background: #c9ccd6; }
.bar-track.energy .bar-fill { background: #7f9cff; }
.bar-track.hp.low .bar-fill { background: var(--loss); }
.lead .bar-track { height: 9px; }

.statuses { display: flex; flex-wrap: wrap; gap: 2px; margin: 0; padding: 0; list-style: none; font-size: 13px; }

.sp { display: flex; align-items: center; gap: 6px; }
.sp-label { font-size: 12px; font-weight: 700; color: var(--muted); }
.pip { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--gold); }
.pip.on { background: var(--gold); }
.pip.held { background: repeating-linear-gradient(45deg, var(--gold) 0 3px, transparent 3px 6px); }

.commands { display: flex; flex-direction: column; gap: 6px; min-height: 120px; }
.commands.waiting, .commands.targeting { justify-content: center; align-items: center; text-align: center; color: var(--muted); }
.commands.targeting { color: var(--text); }
.command-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.command { min-width: 0; min-height: 64px; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; padding: 6px 10px; text-align: left; }
.cmd-type, .cmd-name { max-width: 100%; flex-wrap: wrap; overflow-wrap: break-word; hyphens: auto; }
.command:disabled { opacity: .45; cursor: not-allowed; }
.command.ultimate:not(:disabled) { border-color: var(--gold); }
.cmd-type { display: flex; align-items: center; gap: 6px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.cmd-type kbd { font: inherit; font-size: 10px; padding: 0 4px; border: 1px solid var(--line); border-radius: 4px; }
.cmd-name { font-weight: 700; font-size: 14px; }
.cmd-name small, .reason { font-weight: 400; font-size: 11px; color: var(--muted); }
.tie-note { margin: 0; font-size: 13px; color: var(--gold); }
.hint { margin: 0; font-size: 13px; }

.battle-line { display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 4px 8px; border-radius: 10px; background: var(--panel-2); }
.battle-line p { flex: 1; margin: 0; font-size: 14px; }
.btn.small { min-height: 36px; padding: 0 12px; font-size: 14px; }

.wave-banner { align-self: center; padding: 8px 20px; border-radius: 999px; background: var(--gold); color: var(--on-gold); font: 400 32px/1 var(--font-pixel); text-transform: uppercase; }

.sheet, .result { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 5; display: flex; flex-direction: column; gap: 8px; padding: 14px; border: 1px solid var(--line); border-radius: 14px; background: var(--panel); box-shadow: 0 8px 30px rgba(0, 0, 0, .5); }
.sheet p, .result p { margin: 0; }
.sheet.menu { left: auto; bottom: auto; top: 64px; right: 12px; width: min(280px, calc(100% - 24px)); }
.sheet.log ol { max-height: 50vh; overflow-y: auto; margin: 0; padding-left: 20px; font-size: 14px; }
.result { top: 30%; bottom: auto; text-align: center; }
.result h2 { margin: 0; font: 400 48px/1 var(--font-pixel); color: var(--gold); text-transform: uppercase; }

.float { position: absolute; z-index: 1; transform: translateX(-50%); font: 400 32px/1 var(--font-pixel); text-shadow: 2px 0 0 #000, -2px 0 0 #000, 0 2px 0 #000, 0 -2px 0 #000, 0 3px 0 #000; animation: float-up .85s ease-out forwards; }
.float.dmg { color: #fff; }
.float.weak { color: #ffd166; }
.float.heal { color: #7dff9b; }
.float.brk { color: #ff8f5a; }
@keyframes float-up { from { opacity: 1; transform: translate(-50%, 0); } to { opacity: 0; transform: translate(-50%, -36px); } }
[data-motion="calm"] .float { display: none; }
/* Battle effects (art/effects.json): one row of frames stepped through once
   over the unit, at its sprite's scale, never smoothed, behind the numbers. */
.fx { position: absolute; z-index: 0; background-repeat: no-repeat; background-position: 0 0; image-rendering: pixelated; animation: fx-frames var(--dur) steps(var(--steps)) 1 forwards; }
@keyframes fx-frames { from { background-position-x: 0; } to { background-position-x: var(--to); } }
[data-motion="calm"] .fx { display: none; }
[data-motion="full"] .bar-fill { transition: width .25s ease; }

/* Backdrops (#39): the sacred-grove scene for each view, darkened so the
   cards read over it. The scenes are pixel art, so they scale without
   smoothing. A scene that doesn't load leaves the plain ground colour. */
.battle { background-color: var(--ground); background-position: center; background-size: cover; background-repeat: no-repeat; image-rendering: pixelated; }
[data-battle-view="handheld"] .battle { background-image: linear-gradient(rgba(17, 20, 29, .55), rgba(17, 20, 29, .88)), url('../skin/scenes/sacred-grove-handheld.png'); }
/* The arena's backdrop covers the field and what is above it, from the top:
   at least the battle's width, and at least as tall as the field's bottom
   (the teams' feet; battle.js measures --field-bottom), so its forest is at
   the top and the teams stand on its grass; below, behind the commands, it
   fades into the ground. 2 is the scene's width over its height (576x288).
   Before the first measure it covers the whole battle. */
[data-battle-view="arena"] .battle {
  background-image: linear-gradient(transparent calc(var(--field-bottom, 100%) - 48px), var(--ground) var(--field-bottom, 100%)), linear-gradient(rgba(17, 20, 29, .45), rgba(17, 20, 29, .85)), url('../skin/scenes/sacred-grove-arena.png');
  background-size: auto, auto, max(100%, calc(var(--field-bottom, 50%) * 2)) auto;
  background-position: center, center, center top;
}
.battle-stage { image-rendering: auto; }

/* Thumb controls (#39), handheld only: Basic, Skill and Ultimate in an arc
   in one bottom corner, for one hand. Basic, the most used, sits in the
   corner; Skill and Ultimate fan out from it. */
/* The handheld view's SP and commands, in .controls: without thumb controls
   it takes no box, and they stay in the page's flow. With them, the arc
   fills the corner on the thumb's side, and the SP and whose turn it is sit
   in the free corner on the other side, above Skill, instead of in rows of
   their own, so the cards fit a phone without scrolling. The commands keep
   one height in every state, so nothing above them moves between turns. */
.controls { display: contents; }
:is([data-thumb="right"], [data-thumb="left"]) .controls { display: grid; }
:is([data-thumb="right"], [data-thumb="left"]) .controls > * { grid-area: 1 / 1; min-width: 0; }
:is([data-thumb="right"], [data-thumb="left"]) .controls > .sp { position: relative; z-index: 1; align-self: start; height: 24px; }
[data-thumb="right"] .controls > .sp { justify-self: start; }
[data-thumb="left"] .controls > .sp { justify-self: end; }
:is([data-thumb="right"], [data-thumb="left"]) .controls > .commands { position: relative; min-height: 180px; }
:is([data-thumb="right"], [data-thumb="left"]) .commands .turn-of { position: absolute; top: 30px; }
[data-thumb="right"] .commands .turn-of { left: 0; }
[data-thumb="left"] .commands .turn-of { right: 0; text-align: right; }
:is([data-thumb="right"], [data-thumb="left"]) :is(.tie-note, .commands .countdown) { margin-top: 30px; }
[data-thumb="right"] .command-row, [data-thumb="left"] .command-row { position: relative; display: block; height: 176px; }
[data-thumb="right"] .command, [data-thumb="left"] .command { position: absolute; width: 120px; min-height: 76px; padding: 6px 8px; border-radius: 22px; }
[data-thumb="right"] .command.basic { right: 0; bottom: 0; }
[data-thumb="right"] .command.skill { right: 130px; bottom: 6px; }
[data-thumb="right"] .command.ultimate { right: 10px; bottom: 92px; }
[data-thumb="left"] .command.basic { left: 0; bottom: 0; }
[data-thumb="left"] .command.skill { left: 130px; bottom: 6px; }
[data-thumb="left"] .command.ultimate { left: 10px; bottom: 92px; }
[data-thumb="right"] .commands .hint, [data-thumb="right"] .tie-note { margin-right: 136px; }
[data-thumb="left"] .commands .hint, [data-thumb="left"] .tie-note { margin-left: 136px; text-align: right; }
/* A shorter phone: a tighter arc, its buttons a little lower and Ultimate
   closer above Basic, so the cards fit with it. */
@media (max-height: 800px) {
  :is([data-thumb="right"], [data-thumb="left"]) .command-row { height: 146px; }
  :is([data-thumb="right"], [data-thumb="left"]) .command { min-height: 66px; }
  :is([data-thumb="right"], [data-thumb="left"]) .command.ultimate { bottom: 76px; }
  :is([data-thumb="right"], [data-thumb="left"]) .controls > .commands { min-height: 150px; }
}

/* The arena view (#39): both teams standing on the sacred grove's grass,
   side-on, yours on the left and theirs on the right, as in a side-view
   JRPG; the timeline across the top; the command bar along the bottom with
   SP beside it; the log a line at the bottom, or a column down the right on
   wide screens. */
[data-battle-view="arena"] .app[data-layout="battle"] { max-width: 1440px; }
.battle-stage.arena { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr auto auto; gap: 10px; }
/* The teams stand at the bottom of the field, on the grove's grass in front
   of the commands, not up among the trees and the shrine. */
.arena-field { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 32px; align-items: end; }
.arena-side { --s: 2; display: grid; grid-template-rows: repeat(2, auto); grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-items: end; justify-items: center; gap: 4px 8px; }
/* 3x on a tall landscape screen; a portrait one (the side-on camera held
   upright) keeps 2x, so both teams fit across its width without scrolling. */
@media (min-height: 700px) and (orientation: landscape) { .arena-side { --s: 3; } }
/* The line-up's front (the first two) stands nearest the middle: your side's
   columns run right to left. The second row steps back toward its own edge,
   so each side stands in a loose diagonal rather than a table. */
.arena-side.mine { direction: rtl; }
.arena-side > * { direction: ltr; }
.arena-side.mine > :nth-child(even) { transform: translateX(-18%); }
.arena-side.theirs > :nth-child(even) { transform: translateX(18%); }
/* The arena frame with the camera behind or facing your team: the teams in
   two lines across the field, the far one above the near one. */
.arena-field.lines { grid-template-columns: minmax(0, 1fr); gap: 0; }
.arena-field.lines .ground-side { grid-auto-columns: minmax(0, 200px); justify-content: center; column-gap: 24px; }
@media (min-height: 700px) { .arena-field.lines .ground-side { --s: 3; } }

/* A fighter: no window, just the sprite on the floor with a shadow under
   its feet and a small plate below for its name and meters. The sprite
   draws at --s, a whole multiple, like every sheet. */
.fighter { position: relative; display: flex; flex-direction: column; align-items: center; width: 100%; max-width: 168px; min-width: 0; padding: 0; border: 0; background: none; color: var(--text); font: inherit; text-align: center; }
/* isolation keeps the shadow (z-index -1) inside the fighter, under its
   sprite: without it, a fighter with no transform of its own let its shadow
   fall behind the battle's backdrop, so only the nudged ones showed one. */
.fighter-body { position: relative; display: block; line-height: 0; isolation: isolate; }
.fighter .sheet-sprite { --s: inherit; }
.fighter .sprite:not(.sheet-sprite) { display: block; font-size: calc(var(--s) * 20px); line-height: 1.2; }
/* The heroes' Time Elements cells leave 17px below the feet: the shadow sits
   at the feet, and the plate tucks up into the gap. The monsters' sheets are
   cropped at the feet, so theirs sit at the bottom of the sprite and the
   plate stays below it. */
.fighter-body::after { content: ""; position: absolute; left: 50%; bottom: calc(var(--s) * 15px); z-index: -1; width: calc(var(--s) * 22px); height: calc(var(--s) * 4px); margin-left: calc(var(--s) * -11px); border-radius: 50%; background: rgba(0, 0, 0, .45); }
.fighter.hero:has(.sheet-sprite) .fighter-plate { margin-top: calc(var(--s) * -13px); }
.fighter.monster .fighter-body::after { bottom: calc(var(--s) * -2px); }
.fighter.monster .fighter-plate { margin-top: calc(var(--s) * 3px); }
.fighter.acting .fighter-body::after { background: radial-gradient(closest-side, rgba(237, 195, 41, .85), rgba(237, 195, 41, .25)); }
.fighter.fallen { opacity: .55; }
.fighter.pickable { cursor: pointer; box-shadow: none; }
.fighter-plate { position: relative; display: flex; flex-direction: column; gap: 2px; width: min(100%, 120px); padding: 2px 4px 3px; border-radius: 4px; background: rgba(10, 13, 24, .6); }
.fighter .unit-name { justify-content: center; font-size: 12px; line-height: 1.15; text-shadow: 0 1px 0 #000; }
.fighter.acting .unit-name { color: var(--gold); }
.fighter.chosen .fighter-plate { outline: 2px dashed var(--gold); outline-offset: 1px; }
.fighter .bar-track { height: 5px; }
.fighter .statuses { justify-content: center; font-size: 11px; }
.battle-stage.arena .wave-banner { position: absolute; left: 50%; top: 40%; transform: translateX(-50%); z-index: 3; }
.arena-bottom { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px 16px; }
.arena-bottom .sp { flex: none; padding-bottom: 8px; }
.arena-bottom .commands { flex: 1 1 300px; min-width: 0; min-height: 0; }
.arena-bottom .commands.waiting, .arena-bottom .commands.targeting { min-height: 64px; flex-direction: row; gap: 12px; }
.turn-of { margin: 0; font-size: 14px; }
.arena-log { display: none; }

@media (min-width: 1100px) {
  .battle-stage.arena { grid-template-columns: minmax(0, 1fr) 280px; }
  .battle-stage.arena > :not(.arena-log):not(.sheet):not(.result) { grid-column: 1; }
  .battle-stage.arena .arena-log { display: block; grid-column: 2; grid-row: 1 / span 4; overflow-y: auto; padding: 12px; border-radius: 12px; background: rgba(30, 32, 41, .9); }
  .arena-log ol { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 4px; font-size: 14px; }
  .battle-stage.arena .battle-line { display: none; }
}

/* Short screens (a landscape phone): everything a little tighter, so the whole battle fits without scrolling. */
@media (max-height: 520px) {
  .battle-stage.arena { gap: 6px; padding-top: 4px; padding-bottom: 6px; }
  .arena-side { row-gap: 0; }
  /* Statuses sit beside the name, so a status never makes a fighter taller. */
  .fighter .statuses { position: absolute; top: -14px; left: 0; right: 0; flex-wrap: nowrap; overflow: hidden; }
  .battle-stage.arena .command { min-height: 52px; padding: 4px 10px; }
  .battle-stage.arena .hint, .battle-stage.arena .turn-of { display: none; }
  .battle-stage.arena .battle-line { min-height: 32px; padding: 2px 8px; }
  .battle-stage.arena .battle-line .btn.small { min-height: 30px; }
}

/* The team pick (#44): in portrait, your line-up on top, the roster in the
   middle and Lock in at the bottom; in landscape, your line-up on the left,
   the roster in the middle and the opponent on the right. */
.pick { display: grid; gap: 14px; grid-template-columns: minmax(0, 1fr); grid-template-areas: "lineup" "filters" "roster" "details" "opponent" "lock"; }
.lineup { grid-area: lineup; }
.filters { grid-area: filters; display: flex; flex-direction: column; gap: 6px; }
.roster { grid-area: roster; }
.pick-details { grid-area: details; }
.opponent { grid-area: opponent; }
.lock-zone { grid-area: lock; position: sticky; bottom: 0; padding: 10px 0 calc(10px + env(safe-area-inset-bottom)); background: linear-gradient(transparent, var(--ground) 30%); }
.lock-zone .btn:disabled { opacity: .55; cursor: not-allowed; }

.slots { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr)); gap: 6px; }
.slot { width: 100%; min-height: 64px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 6px; border-radius: 10px; font: inherit; font-size: 12px; text-align: center; color: var(--text); }
.slot.filled { border: 2px solid var(--gold); background: var(--panel); cursor: pointer; }
.slot.empty, .slot.hidden { border: 2px dashed var(--dim); }
.slot.hidden { font: 400 32px/1 var(--font-pixel); color: var(--loss); }
.slot { position: relative; }
.slot-num { position: absolute; left: 6px; top: 4px; font: 700 12px/1 system-ui, -apple-system, 'Segoe UI', sans-serif; color: var(--muted); }
.slot.filled .slot-num { color: var(--gold); }
.slot.empty.next { border-style: solid; border-color: var(--rim); }
.slot .portrait { font-size: 24px; }

.chips { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: thin; }
.chip-filter { flex: none; }
@media (min-width: 720px) { .chips { flex-wrap: wrap; overflow-x: visible; } }
.chip-filter { min-height: 36px; padding: 0 12px; border: 1px solid var(--line); border-radius: 999px; background: var(--panel); color: var(--text); font: inherit; font-size: 14px; cursor: pointer; }
.chip-filter[aria-pressed="true"] { background: var(--text); color: var(--ground); font-weight: 700; }

.pick-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 8px; }
.pick-card-wrap { position: relative; }
.pick-card { position: relative; width: 100%; min-height: 128px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 2px; padding: 10px 6px; border: 2px solid var(--line); border-radius: var(--radius); background: var(--panel); color: var(--text); font: inherit; cursor: pointer; }
.pick-card .portrait { flex: 1; display: grid; place-items: center; font-size: 40px; }
.pick-card .muted { font-size: 12px; text-align: center; }
.pick-card.chosen { border-color: var(--gold); background: var(--panel-attention); }
.pick-card:disabled { opacity: .45; cursor: not-allowed; }
.slot-badge { position: absolute; top: 6px; left: 6px; width: 24px; height: 24px; display: grid; place-items: center; border-radius: 50%; background: var(--gold); color: var(--on-gold); font-weight: 800; font-size: 13px; }
.details-btn { position: absolute; top: 4px; right: 4px; width: 36px; min-height: 36px; border-radius: 50%; font-weight: 800; font-style: italic; }
.pick-details { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2); }
.pick-details h2 { margin: 0; font-size: 18px; }
.pick-details p { margin: 0; }

@media (orientation: landscape) and (min-width: 720px) {
  .app[data-layout="pick"] { max-width: 1280px; }
  .pick { grid-template-columns: 200px minmax(0, 1fr) 200px; grid-template-areas: "lineup filters opponent" "lineup roster opponent" "lineup details opponent" "lock lock lock"; align-items: start; }
  .lineup .slots, .opponent .slots { grid-template-columns: minmax(0, 1fr); }
}

/* Versus in battle: the match clock beside the label, and the result's line-ups. */
.clock { font-size: 13px; color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.lineups { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; font-size: 14px; text-align: left; }

/* The gods' sprites (#8): the whole cell over a box the size of the sheet's
   crop, scaled by a whole number (--s, times a boss's --z) and never smoothed. The cell may
   overflow the box (an attack's swing) without moving the layout. Frames
   step only with motion on; calm shows each state's first frame. */
.sheet-sprite { --s: 1; position: relative; display: inline-block; flex: none; width: calc(var(--bw) * var(--s) * var(--z, 1) * 1px); height: calc(var(--bh) * var(--s) * var(--z, 1) * 1px); overflow: visible; font-size: 0; line-height: 0; vertical-align: middle; }
.sheet-cell { position: absolute; left: calc(var(--cx) * var(--s) * var(--z, 1) * -1px); top: calc(var(--cy) * var(--s) * var(--z, 1) * -1px); width: calc(var(--cw) * 1px); height: calc(var(--ch) * 1px); transform: scale(calc(var(--s) * var(--z, 1))); transform-origin: 0 0; background-repeat: no-repeat; background-position: var(--from) var(--row); image-rendering: pixelated; pointer-events: none; }
[data-motion="full"] .play-loop .sheet-cell { animation: sheet-frames var(--dur) steps(var(--steps)) infinite; }
[data-motion="full"] .play-pingpong .sheet-cell { animation: sheet-frames var(--dur) steps(var(--steps), jump-none) infinite alternate; }
[data-motion="full"] .play-once .sheet-cell { animation: sheet-frames var(--dur) steps(var(--steps), jump-none) 1 forwards; }
@keyframes sheet-frames { from { background-position-x: var(--from); } to { background-position-x: var(--to); } }
.lead .sheet-sprite, .pick-card .sheet-sprite, .god-card .sheet-sprite { --s: 2; }
/* --feet: how far above the sprite's bottom its feet are, in sheet pixels, for
   effects that land on the ground. The gods' Time Elements cells leave 17px
   below the feet; the monsters' sheets are cropped at the feet. */
.sheet-sprite { --feet: 0; }
.sheet-sprite.kind-hero { --feet: 17; }
.splash .sheet-sprite { --s: var(--k); }

/* Sign-in, the profile drawer and the online lobby (#46). */
.error { margin: 0; color: #ff9a8a; }
.help.error { color: #ff9a8a; }
.notice { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2); }
.notice p { margin: 0; }
.drawer-wrap { position: fixed; inset: 0; z-index: 20; display: flex; }
.scrim { position: absolute; inset: 0; border: 0; background: rgba(0, 0, 0, .55); cursor: pointer; }
.drawer { position: relative; width: min(320px, 86vw); height: 100%; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding: calc(16px + env(safe-area-inset-top)) 16px 16px; background: var(--panel); border-right: 1px solid var(--line); }
.drawer h2 { margin: 0; font-size: 20px; overflow-wrap: anywhere; }
.drawer p { margin: 0; }
.text, .invite { width: 100%; min-height: var(--tap); padding: 0 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--ground); color: var(--text); font: inherit; }
.share { padding: 12px; border: 1px solid var(--gold); border-radius: var(--radius); background: var(--panel-2); }
.share p { margin: 0; }
.share .row { justify-content: flex-start; flex-wrap: wrap; }
.lobby > p { margin: 0; }
.matches { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.match-row { display: flex; align-items: center; gap: 8px; padding: 4px 8px 4px 4px; border: 1px solid var(--line); border-left-width: 4px; border-radius: 10px; background: var(--panel); }
.match-row.turn { border-left-color: var(--gold); }
.match-row.win { border-left-color: var(--win); }
.match-row.loss { border-left-color: var(--loss); }
.match-link { flex: 1; min-width: 0; min-height: var(--tap); display: flex; flex-direction: column; justify-content: center; padding: 6px 8px; color: var(--text); text-decoration: none; border-radius: 8px; }
.match-link strong { overflow-wrap: anywhere; }
.match-link .muted { font-size: 14px; }
.row-actions { display: flex; gap: 6px; flex: none; }

/* An online match (#47): waiting, the pick's countdown, the result. */
.online-card { padding: 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2); }
.online-card h2 { margin: 0; }
.online-card p { margin: 0; }
.row.wrap { flex-wrap: wrap; justify-content: flex-start; }
.countdown { margin: 0; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--gold); }
.commands .countdown { text-align: right; font-size: 14px; }
.pick-note { display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 24px; margin-bottom: 6px; }
.locked { margin: 0; padding-left: 22px; display: flex; flex-direction: column; gap: 4px; font-weight: 600; }

/* The landing in landscape (docs/client/DESIGN.md, screen 1; #53): the chip
   stays top left, Play moves to the bottom right, and the icon row runs along
   the bottom beside it. */
@media (orientation: landscape) and (min-width: 560px) {
  [data-screen="landing"] .brand { margin-top: 24px; }
  [data-screen="landing"] .quick { grid-template-columns: repeat(3, minmax(0, 120px)); margin-right: calc(240px + var(--gutter)); }
  [data-screen="landing"] .thumb-zone { position: fixed; right: max(var(--gutter), env(safe-area-inset-right)); bottom: 0; padding: 0 0 calc(16px + env(safe-area-inset-bottom)); background: none; }
  [data-screen="landing"] .thumb-zone .big { width: 240px; min-height: 64px; }
  [data-screen="landing"] .content { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
}
/* A short landscape screen: a smaller name, so the god still shows between it and the buttons. */
@media (orientation: landscape) and (max-height: 500px) {
  .brand h1 { font-size: 24px; }
}

/* The gods gallery's search (#53). */
.search { max-width: 480px; }
.lore-body { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.lore-body .sources { font-size: 14px; }

/* Custom match settings on the create screen (DESIGN.md, screen 3). */
.match-settings summary { min-height: var(--tap); display: flex; align-items: center; flex-wrap: wrap; gap: 4px; cursor: pointer; }
.match-settings[open] summary { margin-bottom: 8px; }
.match-settings .presets { border: 0; margin: 0; padding: 0; }
.setting { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 8px; }
.setting select { min-height: var(--tap); min-width: 0; flex: 0 1 220px; padding: 0 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--ground); color: var(--text); font: inherit; }
.settings-line { font-size: 13px; }
.pick-note { flex-wrap: wrap; }
.match-settings .summary-detail { flex-basis: 100%; font-size: 14px; }

/* UI art (docs/client/ART-PASS.md): while the skin's ui/ui.json is loaded
   (main.js marks the page data-ui-art and sets a --ui-<piece> property for
   each piece), the shared pieces wear the Time Elements window skins, the
   meters and the SP stars. A frame is a 9-slice border image 12px deep over
   a 2px border, on the window's navy gradient, so without the art the same
   elements keep a plain border and their layout. Everything here sits on the
   2x grid and is never smoothed. */
:root[data-ui-art] :is(.btn, .card, .tile, .god-card, .pick-card, .ability, .lore, .notice, .online-card, .share, .pick-details, .sheet, .result, .bar-track, .pip) { image-rendering: pixelated; }
:root[data-ui-art] :is(.btn, .card, .tile, .god-card, .pick-card, .ability, .lore, .notice, .online-card, .share, .pick-details, .sheet, .result) {
  border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame) 6 / 12px;
  background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box;
}
:root[data-ui-art] :is(.card, .ability, .lore, .notice, .online-card, .share, .pick-details, .sheet, .result) { padding: 14px 16px; }
:root[data-ui-art] .tile { padding: 8px; }
/* The gods' cards are showcase pieces: the skins with gem corners. */
:root[data-ui-art] :is(.god-card, .pick-card) { border-image-source: var(--ui-frame-showcase); padding: 12px 8px; }
:root[data-ui-art] :is(.card[aria-checked="true"], .share) { border-image-source: var(--ui-frame-attention); }
:root[data-ui-art] .pick-card.chosen { border-image-source: var(--ui-frame-showcase-attention); }
:root[data-ui-art] :is(.pick-card, .btn):disabled { border-image-source: var(--ui-frame-dim); }
:root[data-ui-art] .btn { padding: 0 18px; }
:root[data-ui-art] .btn.primary { border-image-source: var(--ui-frame-showcase-attention); background: var(--gold); box-shadow: inset 0 -6px 0 rgba(107, 76, 0, .45); }
:root[data-ui-art] .btn.icon-btn { padding: 0; }
/* A round button too small for the frame's corners keeps a plain rim. */
:root[data-ui-art] .btn.details-btn { border: 2px solid var(--rim); border-image: none; border-radius: 50%; padding: 0; background: var(--panel); }
:root[data-ui-art] .bar-track { height: var(--ui-meter-h); border: 6px solid transparent; border-radius: 0; border-image: var(--ui-meter) 3 fill / 6px; background: none; overflow: hidden; }
:root[data-ui-art] .bar-fill { background: var(--ui-fill-hp) 0 0 / 100% 100%; }
:root[data-ui-art] .bar-track.tough .bar-fill { background: var(--ui-fill-tough) 0 0 / 100% 100%; }
:root[data-ui-art] .bar-track.energy .bar-fill { background: var(--ui-fill-energy) 0 0 / 100% 100%; }
:root[data-ui-art] .pip { width: var(--ui-pip-w); height: var(--ui-pip-h); border: 0; border-radius: 0; background: var(--ui-pip-empty) center / 100% 100% no-repeat; }
:root[data-ui-art] .pip.on { background: var(--ui-pip) center / 100% 100% no-repeat; }
:root[data-ui-art] .pip.held { background: var(--ui-pip) center / 100% 100% no-repeat; opacity: .5; }

/* Icons from the UI art (dom.js glyph): elements, statuses, and later the
   HUD's. On the 2x grid when they stand alone; at their pack's own size when
   they sit in a line of text, where a 32px icon would tower over the words. */
.ui-icon { display: inline-block; flex: none; width: var(--icon-w); height: var(--icon-h); background: var(--icon) center / 100% 100% no-repeat; image-rendering: pixelated; vertical-align: middle; }
.ui-icon.inline { width: calc(var(--icon-w) / 2); height: calc(var(--icon-h) / 2); vertical-align: -3px; }
.el-label { display: inline-flex; align-items: center; gap: 4px; }
.ui-icon.large { width: calc(var(--icon-w) * 1.5); height: calc(var(--icon-h) * 1.5); }
/* The landing's chip is a small window too, with a square portrait. */
:root[data-ui-art] .chip { border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame) 6 / 12px; background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; padding: 6px 16px 6px 8px; image-rendering: pixelated; }
:root[data-ui-art] .chip .avatar { border-radius: 0; background: rgba(0, 0, 0, .4); }
:root[data-ui-art] .emblem { border-radius: 0; }

/* The dungeon between floors (#281): the party, the shop, the next floor. */
.dungeon h2 { margin: 0; }
.dungeon .gold { font-size: 18px; }
.party-list { display: flex; flex-direction: column; gap: 8px; }
.hero-row { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 56px; padding: 6px 10px; border: 2px solid var(--line); border-radius: 12px; background: var(--panel); color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.hero-row.chosen { border-color: var(--accent); }
.hero-row.fallen { opacity: .7; }
.hero-row .portrait { width: 48px; height: 48px; flex: none; display: grid; place-items: center; font-size: 28px; }
.hero-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.hero-info .bar-track { display: block; height: 6px; border-radius: 3px; background: var(--panel-2); overflow: hidden; }
.hero-info .bar-fill { display: block; height: 100%; background: #5fbf7a; }
.hero-info .down { color: #ff9a8a; font-weight: 700; font-size: 13px; }
.small { font-size: 13px; }
.shop-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.shop-row { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); }
.shop-icon { font-size: 22px; width: 28px; text-align: center; flex: none; }
.shop-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.shop-row .btn:disabled { opacity: .5; cursor: not-allowed; }

/* The battle HUD in the art (ART-PASS.md step 2). Units sit in windows: yours
   blue-silver, the one acting gold, the fallen dim. A unit you can target now
   wears the target arrow, bobbing with motion on. The timeline marks each
   side by its frame, blue for yours and red for theirs, gold for now. */
:root[data-ui-art] :is(.unit, .lead, .battle-line, .arena-log, .timeline li) {
  border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame) 6 / 12px;
  background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; image-rendering: pixelated;
}
:root[data-ui-art] :is(.unit, .lead) { position: relative; padding: 10px 12px; box-shadow: none; }
/* On a shorter phone the lead card is a little flatter, so the battle fits (see .party + .controls > .sp). */
@media (max-height: 800px) { .battle-stage .lead, :root[data-ui-art] .battle-stage .lead { padding-top: 6px; padding-bottom: 6px; } }
:root[data-ui-art] .battle-line { padding: 6px 8px 6px 14px; }
:root[data-ui-art] .battle-stage.arena .arena-log { padding: 14px 16px; }
:root[data-ui-art] :is(.unit, .lead).acting { border-image-source: var(--ui-frame-attention); }
:root[data-ui-art] :is(.unit, .lead).fallen { border-image-source: var(--ui-frame-dim); }
:root[data-ui-art] .unit.chosen { border-style: solid; border-image-source: var(--ui-frame-showcase); }
:root[data-ui-art] :is(.unit, .lead).pickable { border-image-source: var(--ui-frame-showcase-attention); }
:root[data-ui-art] .pickable::before {
  content: ""; position: absolute; left: 50%; top: calc(-1 * var(--ui-icon-target-h) + 4px); z-index: 2;
  width: var(--ui-icon-target-w); height: var(--ui-icon-target-h); margin-left: calc(var(--ui-icon-target-w) / -2);
  background: var(--ui-icon-target) center / 100% 100% no-repeat; pointer-events: none;
}
[data-motion="full"][data-ui-art] .pickable::before { animation: target-bob .8s steps(2, jump-none) infinite alternate; }
@keyframes target-bob { from { transform: translateY(-2px); } to { transform: translateY(2px); } }
:root[data-ui-art] .timeline li { padding: 0; border-image-width: 6px; }
:root[data-ui-art] .timeline li.theirs { border-image-source: var(--ui-frame-foe); }
:root[data-ui-art] .timeline li.now { border-image-source: var(--ui-frame-attention); }
:root[data-ui-art] .bar-track.hp.low .bar-fill { background: var(--ui-fill-low) 0 0 / 100% 100%; }
:root[data-ui-art] .command.ultimate:not(:disabled) { border-image-source: var(--ui-frame-attention); }
:root[data-ui-art] .wave-banner { border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame-showcase-attention) 6 / 12px; padding: 12px 22px; image-rendering: pixelated; }
.cmd-name .energy { white-space: nowrap; }
/* Three commands share a 400px row: the frame's corners need less room than a plain button's padding. */
:root[data-ui-art] .btn.command { padding: 8px 12px; }
/* A narrow phone: the longest one-word names (Psychopomp, Thunderbolt) need
   about 90px at 14px, more than a third of the row leaves inside the usual
   padding. Less side padding, then a smaller name, keep each word whole; a
   name still too long breaks with a hyphen rather than mid-word. */
@media (max-width: 420px) {
  .command, :root[data-ui-art] .btn.command { padding-left: 8px; padding-right: 8px; }
}
@media (max-width: 380px) {
  .cmd-name { font-size: 13px; }
}
/* The fighters' plates carry the meters at their art's own size (1x): small
   under a sprite, as in a side-view JRPG. A landscape phone also tightens the
   commands and the log line, so the whole battle fits without scrolling. */
:root[data-ui-art] .fighter .bar-track { height: calc(var(--ui-meter-h) / 2); border-width: 3px; border-image-width: 3px; }
@media (max-height: 520px) {
  :root[data-ui-art] .battle-stage.arena .btn.command { padding: 4px 12px; }
  :root[data-ui-art] .battle-stage.arena .battle-line { padding: 0 6px 0 10px; border-image-width: 6px; }
}

/* The team pick and the gallery (ART-PASS.md step 4). A god's card shows them
   standing on the sacred grove's path, both at 2x, with the name in the
   pixel font. Line-up slots: gold when filled, blue-silver for the next to
   fill, dim for the rest; the opponent's hidden slots in the red frame. */
:is(.pick-card, .god-card) .portrait { align-self: stretch; min-height: 72px; background: url('../skin/scenes/sacred-grove-handheld.png') center 72% / 512px 576px no-repeat; image-rendering: pixelated; }
/* A gallery card's name in pixel type; the pick's three narrow columns are too tight for it at 32px, so there the name is the system font in bold. */
.god-card strong { font: 400 32px/1 var(--font-pixel); text-shadow: var(--pixel-shadow); }
.pick-card strong { font-weight: 700; font-size: 15px; }
:root[data-ui-art] :is(.slot, .chip-filter, .text.search) {
  border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame) 6 / 12px;
  background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; image-rendering: pixelated;
}
:root[data-ui-art] .slot { padding: 12px 8px 8px; }
:root[data-ui-art] .slot.filled { border-image-source: var(--ui-frame-attention); }
:root[data-ui-art] .slot.empty:not(.next) { border-image-source: var(--ui-frame-dim); background: rgba(0, 0, 0, .35); }
:root[data-ui-art] .slot.hidden { border-image-source: var(--ui-frame-foe); }
:root[data-ui-art] .slot-num { left: 10px; top: 8px; }
:root[data-ui-art] .chip-filter { padding: 0 14px; }
:root[data-ui-art] .chip-filter[aria-pressed="true"] { border-image-source: var(--ui-frame-attention); background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; color: var(--gold); }
:root[data-ui-art] .text.search { padding: 0 16px; }
:root[data-ui-art] .slot-badge { border-radius: 0; box-shadow: 0 0 0 2px #000; }
.countdown .ui-icon { vertical-align: -3px; }
/* A primary button that can't be pressed yet (Lock in before the line-up is full) is a plain dim window, not a muddy gold. */
:root[data-ui-art] .btn.primary:disabled { border-image-source: var(--ui-frame-dim); background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; color: var(--muted); box-shadow: none; opacity: 1; }
:root[data-ui-art] :is(.hero-banner, .stats) { border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame-showcase) 6 / 12px; }
:root[data-ui-art] .stats { border-image-source: var(--ui-frame); background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; padding: 14px 16px; image-rendering: pixelated; }
:root[data-ui-art] .bar-track.atk .bar-fill { background: var(--ui-fill-low) 0 0 / 100% 100%; }
:root[data-ui-art] .bar-track.def .bar-fill { background: var(--ui-fill-gold) 0 0 / 100% 100%; }
:root[data-ui-art] .bar-track.spd .bar-fill { background: var(--ui-fill-energy) 0 0 / 100% 100%; }

/* The result, the lobby and the profile (ART-PASS.md step 6). A result looks
   like its outcome: Victory gold, with a glow and a star; Defeat in the red
   frame; a draw or no result plain. Match rows are windows: gold when the
   match waits on you, a green or red stripe for a win or a loss, dim when it
   ended with no result. */
.result-card { text-align: center; }
.result-card h2 { font: 400 48px/1 var(--font-pixel); color: var(--gold); text-transform: uppercase; }
:is(.result, .result-card).tone-win h2 { text-shadow: 0 3px 0 var(--gold-deep), 0 0 18px rgba(237, 195, 41, .45); }
:is(.result, .result-card).tone-loss h2 { color: #e0787a; text-shadow: 0 3px 0 #000; }
:is(.result, .result-card).tone-none h2 { color: var(--text); text-shadow: 0 3px 0 #000; }
:root[data-ui-art] :is(.result, .result-card).tone-win { border-image-source: var(--ui-frame-showcase-attention); box-shadow: 0 0 40px rgba(237, 195, 41, .22), 0 8px 30px rgba(0, 0, 0, .5); }
:root[data-ui-art] :is(.result, .result-card).tone-win h2::after { content: ""; display: block; width: var(--ui-icon-sp-w); height: var(--ui-icon-sp-h); margin: 10px auto 0; background: var(--ui-icon-sp) center / 100% 100% no-repeat; image-rendering: pixelated; }
:root[data-ui-art] :is(.result, .result-card).tone-loss { border-image-source: var(--ui-frame-foe); }
.match-row { position: relative; }
:root[data-ui-art] .match-row {
  border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame) 6 / 12px;
  background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; padding: 8px 12px 8px 18px; image-rendering: pixelated;
}
:root[data-ui-art] .match-row.turn { border-image-source: var(--ui-frame-attention); }
:root[data-ui-art] .match-row.none { border-image-source: var(--ui-frame-dim); }
:root[data-ui-art] .match-row:is(.win, .loss)::before { content: ""; position: absolute; left: 10px; top: 12px; bottom: 12px; width: 4px; background: var(--win); }
:root[data-ui-art] .match-row.loss::before { background: var(--loss); }
:root[data-ui-art] .match-row.turn .match-link strong { color: var(--gold); }

/* Settings, credits and the profile (ART-PASS.md step 7). Each group is a
   window; a fieldset's legend floats, so it sits inside the frame rather
   than on its top edge. A segmented choice is a dark strip with the chosen
   option in the gold frame. Text fields and the profile drawer are windows
   too. */
:root[data-ui-art] :is(.group, .drawer, .text, .invite) {
  border: 2px solid transparent; border-radius: 0; border-image: var(--ui-frame) 6 / 12px;
  background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; image-rendering: pixelated;
}
:root[data-ui-art] .group { padding: 14px 16px; }
:root[data-ui-art] fieldset.group > legend { float: left; width: 100%; }
:root[data-ui-art] fieldset.group > legend + * { clear: both; }
:root[data-ui-art] :is(.text, .invite) { padding: 0 16px; }
:root[data-ui-art] .drawer { padding-left: 20px; padding-right: 20px; }
:root[data-ui-art] .segmented { border-radius: 0; background: rgba(0, 0, 0, .35); padding: 4px; }
:root[data-ui-art] .segmented span { border-radius: 0; color: var(--muted); }
:root[data-ui-art] .segmented input:checked + span {
  border: 2px solid transparent; border-image: var(--ui-frame-attention) 6 / 12px;
  background: var(--ui-window) 0 0 / 100% 100% no-repeat border-box; color: var(--gold); image-rendering: pixelated;
}
/* Pressed (the owner's choice, 2026-11-05): a button, tile, card or chip
   lights up gold while it's held down, the same gold as attention; the
   primary button, gold already, presses in. Without the art, a gold border. */
:is(.btn, .tile, .card, .chip-filter, .god-card, .pick-card, .match-link):active:not(:disabled) { border-color: var(--gold); }
:root[data-ui-art] :is(.btn, .tile, .card, .chip-filter, .god-card, .pick-card, .slot.filled):active:not(:disabled) { border-image-source: var(--ui-frame-attention); color: var(--gold); }
:root[data-ui-art] :is(.god-card, .pick-card):active:not(:disabled) { border-image-source: var(--ui-frame-showcase-attention); }
:root[data-ui-art] .btn.primary:active:not(:disabled) { border-image-source: var(--ui-frame-showcase-attention); color: var(--on-gold); box-shadow: inset 0 3px 0 rgba(107, 76, 0, .45); }
