/* src/styles/app.css — the client's own screens (play.html): sign-in, the
   characters list, the character strip and the box the World pane fills.
   Reads tokens only (src/styles/tokens.css loads first); declares none. */
.client-page {
  margin: 0;
  min-height: 100vh;
  background: var(--bg-0);
  color: var(--ink);
  font-family: var(--f-ui);
  /* Alegreya Sans defaults to old-style figures; a HUD of counts and clocks
     reads in lining ones (a "1" that is not a small "i"). */
  font-variant-numeric: lining-nums;
}
.app.is-auth { min-height: 100vh; display: grid; place-items: center; }
/* THE ONE SCROLLBAR for every scroll area of the game (Tyler 2026-10-25), thin steel with a dim gold thumb (tokens.css
   --scroll-*): the standard properties (Firefox, Chromium) and the -webkit- parts (Safari, an older Chromium). Zero
   specificity, so a box that hides its bar on purpose (a category row that pans) keeps doing so. */
:where(*) { scrollbar-width: thin; scrollbar-color: var(--scroll-thumb) var(--scroll-track); }
:where(*:hover) { scrollbar-color: var(--scroll-thumb-hover) var(--scroll-track); }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: var(--scroll-track); }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); }
/* clip, never hidden: a hidden box still scrolls when told to (a focus, a scroll-into-view), and at 667 x 375 a
   too-wide child slid the whole game 102 px off the left edge, the icon row with it (phone-touch PH-1). */
.app.is-game { height: 100vh; display: flex; flex-direction: column; overflow: clip; }

/* ── The account screens (sign-in, the characters, hero creation, the closed notice): the crest and the
   name beside ONE card in FORGED STEEL (Tyler approved the skin on 2026-10-24; ART_DIRECTION §9, §10),
   built from the pieces a window wears: the steel frame over its grained floor, a dark title band ruled in
   dim gold with the card's name in Cinzel, sunk fields, steel rules between the parts, the one primary a
   raised gold plate (shell.css; the button carries .hh-tool.is-primary). Nothing here fades with the Window
   opacity setting: no World is behind these screens. The crest is painted art: 1:1 (311x384) on desktop,
   exactly 1:2 on the phone size class, never at a fraction between. ── */
.auth {
  width: 100%; box-sizing: border-box;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 20px 56px;
  padding: 24px;
}
.auth-brand { display: flex; flex-direction: column; align-items: center; gap: 4px; margin: 0; }
.auth-crest { display: block; width: 311px; height: 384px; }
/* What the game is, for someone who followed a friend's link: under the crest where a sign-in or a sign-up is asked for. */
.auth-card.is-sent .auth-field, .auth-card.is-sent .auth-submit { display: none; }
/* Sent: the answer says it all. The lead and the password's rule are words about a form that has gone (phone panel v0.2.83). */
.auth-card.is-sent .auth-lead { display: none; }
.auth-pitch { display: none; max-width: 311px; margin: 0; font-size: var(--t-small); line-height: 1.35; color: var(--ink); text-align: center; }
.auth:has(.auth-card[data-auth]) .auth-pitch { display: block; }
/* THE LEGAL LINE (src/app/sign-in.js): under the pitch, in the crest's column, which has room where the card has none on a phone.
   The sign-up's is a sentence with two links in it; the sign-in's is the two links alone, pressed like any link here. */
.auth-legal { max-width: 311px; margin: 8px 0 0; font-size: var(--t-small); line-height: 1.35; color: var(--ink-2); text-align: center; }
.auth-legal:not(.is-links) .auth-link { display: inline; min-height: 0; padding: 0; font-size: inherit; text-decoration: underline; text-underline-offset: 3px; }
.auth-legal.is-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 16px; }
/* THE READER (src/app/legal-reader.js): the Privacy Policy or the Terms over the screen, the card's own frame and title band, the text scrolling inside it. */
.auth-doc { position: fixed; inset: 0; z-index: 40; box-sizing: border-box; display: grid; place-items: center; padding: 16px; background: color-mix(in srgb, var(--bg-0) 92%, transparent); }
.auth-card.auth-doc-card { width: min(46rem, 100%); max-height: 100%; min-height: 0; }
.auth-doc-head { justify-content: space-between; gap: 12px; }
.auth-doc-name { margin: 0; font: inherit; letter-spacing: inherit; color: inherit; }
.auth-doc-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 4px 6px 4px 0; font-size: var(--t-small); line-height: 1.5; color: var(--ink); }
.auth-doc-body:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.auth-doc-body h2, .auth-doc-body h3, .auth-doc-body h4 { margin: 1.1em 0 .35em; font-family: var(--f-display); font-weight: 700; line-height: 1.2; letter-spacing: .06em; color: var(--gold-2); }
.auth-doc-body h2 { font-size: var(--t-lead); }
.auth-doc-body h3, .auth-doc-body h4 { font-size: var(--t-body); }
.auth-doc-body :first-child { margin-top: 0; }
.auth-doc-body p, .auth-doc-body ul, .auth-doc-body blockquote { margin: 0 0 .7em; }
.auth-doc-body ul { padding-left: 1.3em; }
.auth-doc-body li { margin-bottom: .3em; }
.auth-doc-body blockquote { padding: 4px 0 4px 12px; border-left: 3px solid var(--steel-rule); color: var(--ink-2); }
.auth-doc-body strong { color: var(--ink); }
.auth-doc-body a { color: var(--gold-2); }
.auth-doc-body hr { border: 0; border-top: 2px solid var(--steel-sep); margin: 1em 0; }
.auth-name {
  margin: 0;
  font-family: var(--f-display); font-weight: 700; font-size: var(--t-h2);
  letter-spacing: .12em; color: var(--gold-2);
}
.auth-card {
  width: min(26rem, 100%); box-sizing: border-box;
  display: flex; flex-direction: column; gap: 12px;
  padding: 0 20px 18px;
  background: url('../../assets/ui/steel-grain.png') 0 0 / 64px 64px repeat, var(--bg-1); background-clip: padding-box;
  border: 12px solid transparent; border-radius: 0;
  border-image: url('../../assets/ui/steel-frame.png') 6 / 12px stretch;
  image-rendering: pixelated;
  box-shadow: 0 10px 28px color-mix(in srgb, var(--world-shadow) 55%, transparent);
}
.auth-card > * { image-rendering: auto; }
/* The title band: the card's name in Cinzel gold on a dark band ruled in dim gold, edge to edge inside the frame. */
.auth-title {
  display: flex; align-items: center; min-height: 44px; margin: 0 -20px 2px; padding: 6px 20px; box-sizing: border-box;
  background: var(--bg-0); border-bottom: 2px solid var(--steel-rule);
  font-family: var(--f-display); font-weight: 700; font-size: var(--t-lead); line-height: 1.15; letter-spacing: .12em; color: var(--gold-2);
}
.auth-lead { margin: 0; font-size: var(--t-small); color: var(--ink-2); line-height: 1.4; }
.auth-field { display: flex; flex-direction: column; gap: 4px; font-family: var(--f-label); font-weight: 700; font-size: var(--t-micro); letter-spacing: .04em; color: var(--ink-2); }
/* A sunk field: a well one art px deep (--steel-well), never a hairline box. */
.auth-field input {
  font-family: var(--f-ui); font-weight: 400; font-size: var(--t-body); letter-spacing: 0;
  min-height: 40px; box-sizing: border-box;
  color: var(--ink);
  background: var(--bg-0);
  border: 0;
  border-radius: 0;
  box-shadow: var(--steel-well);
  padding: 0 10px;
  cursor: text;
}
.auth-field input::placeholder { color: var(--ink-3); }
.auth-field input:focus-visible { outline: 2px solid var(--gold); outline-offset: 0; }
.auth-message { margin: 0; min-height: 1.3em; font-size: var(--t-small); color: var(--red); line-height: 1.3; }
.auth-message:empty { min-height: 0; }
.auth-message.is-good { color: var(--green); }
/* The gold plate itself is shell.css's (.hh-tool.is-primary); a form's one action spans the card. */
.auth-submit { min-height: 44px; font-size: var(--t-body); letter-spacing: .1em; }
.auth-submit:disabled { cursor: progress; }
.auth-links { margin: 0; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 16px; padding-top: 10px; border-top: 2px solid var(--steel-sep); }
.auth-link {
  font-family: var(--f-ui); font-size: var(--t-small);
  color: var(--gold-2);
  background: none;
  border: 0;
  padding: 2px 0;
  cursor: pointer;
  text-decoration: none;
}
.auth-link:hover, .auth-link:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.auth-link:focus-visible { outline: 2px solid var(--aqua-2); outline-offset: 2px; }
/* THE ACCOUNT ID (the closed notice, closed-notice.js): sunk like a field, whole on one line wherever it fits, one press selects it all. */
.auth-id { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.auth-id-value { flex: 1 1 18em; min-height: 36px; box-sizing: border-box; display: flex; align-items: center; padding: 4px 10px; background: var(--bg-0); box-shadow: var(--steel-well);
  font-family: var(--f-ui); font-size: var(--t-micro); font-variant-numeric: tabular-nums; color: var(--ink); overflow-wrap: anywhere; -webkit-user-select: all; user-select: all; }
.auth-id-value::selection { background: var(--gold); color: var(--bg-0); }
.auth-id .hh-tool { min-height: 36px; padding: 0 14px; box-shadow: inset 0 0 0 2px var(--steel-sep); }
/* A card's foot with a way back and a way on (hero creation): back at the left, the gold plate at the right. */
.auth-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 -20px -18px; padding: 10px 20px 12px; border-top: 2px solid var(--steel-sep); background: var(--bg-1); }
.auth-foot .auth-submit { padding: 0 16px 0 20px; }
/* A press that goes somewhere carries the dark steel arrow (as the Hunts window's Enter does). */
.auth-submit.is-go::after { content: ''; display: inline-block; width: 6px; height: 10px; margin-left: 10px; vertical-align: 1px;
  background: url('../../assets/ui/steel-arrow.png') 0 0 / 6px 10px no-repeat; image-rendering: pixelated; }

/* Landscape phone: the crest (1:2) beside the card, both inside 423 px with no scroll. */
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .auth { flex-wrap: nowrap; gap: 40px; padding: 4px 16px; }
  .auth-crest { width: 156px; height: 192px; }
  .auth-card { gap: 6px; padding: 0 16px 12px; }
  .auth-title { min-height: 40px; margin: 0 -16px 0; padding: 4px 16px; }
  .auth-field input { min-height: 36px; }
  .auth-submit { min-height: 40px; }
  .auth-links { padding-top: 2px; }
  /* A thumb's press, not a line of text (phone playtest 2026-10-31: 24 px). */
  .auth-link { min-height: var(--tap); padding: 0 8px; }
  a.auth-link { display: inline-flex; align-items: center; }   /* its words in the middle of the press, level with a button's */
  .auth-id .hh-tool, .auth-id-value { min-height: var(--tap); }
  .auth-links .auth-link:first-child { margin-left: -8px; }
  .auth-links .auth-link:last-child { margin-right: -8px; }
  .auth-foot { margin: 0 -16px -12px; padding: 6px 16px 8px; }
  /* CREATE ACCOUNT FITS (panel 2026-11-01: Back to sign in at y 373 of 375): the two passwords share a row, their rule under them. */
  .auth-card[data-auth="create"] { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 10px; }
  .auth-card[data-auth="create"] > * { grid-column: 1 / -1; }
  .auth-card[data-auth="create"] > .auth-field:nth-of-type(n + 2) { grid-column: auto; }
  .auth-card[data-auth="create"] > .auth-field:nth-of-type(n + 2) ~ * { order: 1; }
  .auth-card[data-auth="create"] > .auth-field:last-of-type { order: 0; }
  /* A screen still too short (a wider font, a keyboard) scrolls, from its top. */
  .app.is-auth { height: 100vh; overflow-y: auto; place-items: start center; }
  .auth { min-height: 100%; }
}

/* ── YOUR CHARACTERS: one steel list, a row per owned slot. The whole row is the press (Play, Show, Create
   hero), its word in Cinzel gold at the right; pointed at, it lifts and takes the picked row's gold outline
   and bar (the Hunts list). An empty slot reads quiet until pointed at. ── */
.char-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; background: var(--bg-0); border: 2px solid var(--steel-edge); }
.char-row + .char-row { border-top: 2px solid var(--steel-sep); }
.char-pick {
  width: 100%; min-height: 56px; box-sizing: border-box;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 14px 8px 18px; border: 0; border-radius: 0; background: var(--bg-2); color: var(--ink);
  font: inherit; text-align: left; cursor: pointer;
}
.char-pick:hover, .char-pick:focus-visible { background: var(--bg-3); box-shadow: inset 0 0 0 2px var(--gold), inset 6px 0 0 var(--gold); outline: none; }
.char-name { display: flex; flex-direction: column; min-width: 0; }
.char-name b { font-size: var(--t-lead); font-weight: 700; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.char-level { font-size: var(--t-micro); font-weight: 400; color: var(--ink-2); font-variant-numeric: lining-nums tabular-nums; }
.char-go { flex: none; font-family: var(--f-display); font-weight: 700; font-size: var(--t-small); letter-spacing: .1em; color: var(--gold-2); }
.char-row.is-empty .char-pick { background: var(--bg-1); }
.char-row.is-empty .char-name b { font-weight: 400; color: var(--ink-3); }
.char-row.is-empty .char-pick:hover b, .char-row.is-empty .char-pick:focus-visible b { color: var(--ink-2); }
/* The next hero slot for sale (src/app/slot-offer.js), behind a steel rule: the price over the account's gold, a
   steel button beside the gold. Never the gold plate: spending gold is a deliberate press, and Play is this
   card's primary. */
.slot-offer { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 14px; padding-top: 10px; border-top: 2px solid var(--steel-sep); }
.slot-offer-lead, .slot-offer-purse, .slot-offer-short { grid-column: 1; margin: 0; font-size: var(--t-small); line-height: 1.4; }
.slot-offer-lead { grid-column: 1 / -1; color: var(--ink); }
.slot-offer-purse { color: var(--ink-2); font-variant-numeric: lining-nums tabular-nums; }
.slot-offer-short { color: var(--ink-3); }
.slot-offer-buy {
  grid-column: 2; grid-row: 2 / span 2; align-self: start; min-height: 40px; padding: 0 12px; white-space: nowrap;
  border: 2px solid var(--steel-btn); border-radius: 0; background: var(--bg-2); color: var(--ink);
  font-family: var(--f-ui); font-weight: 700; font-size: var(--t-small); line-height: 1.2; font-variant-numeric: lining-nums tabular-nums; cursor: pointer;
}
.slot-offer-buy:hover:not(:disabled) { background: var(--bg-3); border-color: var(--gold-3); }
.slot-offer-buy:focus-visible { outline: 2px solid var(--aqua-2); outline-offset: 2px; }
.slot-offer-buy:disabled { opacity: .5; cursor: default; }
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .char-pick { min-height: 48px; padding: 4px 12px 4px 16px; }
  .slot-offer { gap: 2px 12px; padding-top: 6px; }
}

/* Forged Steel: the strip stands on a steel edge (the thin frame's bottom run, 3 art px = 6 px) over the World. */
.char-strip {
  display: flex;
  align-items: stretch;
  gap: 0.25rem;
  padding: 0 0.5rem;
  background: var(--bg-1);
  border-bottom: 6px solid transparent;
  border-image: url('../../assets/ui/steel-frame-thin.png') 3 / 0 0 6px 0 stretch;
  image-rendering: pixelated;
  flex-shrink: 0;
}
/* One tab per open character (src/app/character-strip.js): role, name, doing, three thin bars, the alert badge. */
.char-tabs { display: flex; gap: 2px; margin: 0; padding: 0; list-style: none; min-width: 0; flex: 0 1 auto; overflow: hidden; }
.char-tab-row { display: flex; min-width: 0; }
.char-tab {
  position: relative;
  display: flex; align-items: center; gap: 6px;
  min-width: 0; max-width: 360px;
  font: inherit; font-size: 0.85rem; text-align: left;
  color: var(--ink-2);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 4px 8px 3px;
  cursor: pointer;
}
.char-tab:hover { color: var(--ink); background: var(--bg-2); }
.char-tab:focus-visible, .char-tool:focus-visible { outline: 2px solid var(--aqua-2); outline-offset: -2px; }
.char-tab.is-shown { color: var(--gold-2); border-bottom-color: var(--gold); }
.char-roleglyph { width: 22px; height: 22px; flex: none; display: grid; place-items: center; color: var(--ink-3); }
.char-tab.is-shown .char-roleglyph { color: var(--gold-2); }
.char-roleglyph .hs-glyph { width: 18px; height: 18px; fill: currentColor; }
.char-tab-main { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.char-tab-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.char-tab-doing { font-size: var(--t-micro); font-size-adjust: var(--f-ui-aspect); color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.char-tab.is-hunting .char-tab-doing { color: var(--ink-2); }
.char-bars { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; width: 96px; }
.char-bar { position: relative; display: block; height: 3px; background: var(--bg-0); overflow: hidden; }
.char-bar > i { position: absolute; top: 0; left: 0; bottom: 0; width: 0; background: var(--ink-3); }
.char-bar.is-hp > i { background: var(--hud-fill-hp); }
.char-bar.is-mana > i { background: var(--gem); }
.char-bar.is-stamina > i { background: var(--hud-fill-stamina); }
.char-badge { display: none; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--red); color: var(--bg-0); font-size: var(--t-micro); font-weight: 700; line-height: 18px; text-align: center; }
.char-badge.is-on { display: inline-block; }
/* The tools stand at the strip's right end, never behind the tabs: a tab arriving or a hero's status changing slid Characters under
   a pointer aimed at Sign out (Andy 2026-11-06, client-boot B-4). */
.char-strip-tools { display: flex; align-items: stretch; flex: none; margin-left: auto; }
.char-tool { font: inherit; font-size: 0.85rem; color: var(--ink-3); background: none; border: 0; padding: 0 0.6rem; cursor: pointer; }
.char-tool:hover { color: var(--ink); }
.char-tool-short, .char-tool-now, .char-tool .char-all-badge { display: none; }
.game { flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative; }
.game #panel-world { flex: 1; min-height: 0; padding: 8px; }
/* THE STRIP ON A PHONE (phone playtest 2026-10-31: the tabs squashed to 12 px, and at 667 px the icon row lay over All
   characters, Characters and Sign out). One row 40 px tall, the icon row's own height, its foot where the World already
   started: first "Heroes", the All characters sheet that also holds Character list and Sign out, with the count of
   alerts waiting; then the tabs, thumb-wide and viewed one first, panning under the thumb. Where the icon row leaves no
   room for a tab (the container query: the strip's padding already clears the row) Heroes is the way to them. */
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .char-strip { box-sizing: border-box; height: 40px; padding-left: 2px; gap: 0; align-items: flex-start; container: char-strip / inline-size; }
  .game #panel-world { padding-top: 2px; }
  .char-strip-tools { order: -1; height: 40px; margin-left: 0; }
  .char-tool { position: relative; height: 40px; padding: 0 4px; font-size: var(--t-micro); font-weight: 700; color: var(--ink-2); }
  .char-tool:not(.is-all), .char-tool-wide { display: none; }
  .char-tool.is-all { box-sizing: border-box; width: 58px; padding: 0; } /* the row gives back 60 px (shell.css), whichever font the word lands in */
  .char-tool-short { display: inline; }
  .char-tool .char-all-badge.is-on { display: block; position: absolute; top: 0; right: 0; min-width: 16px; height: 16px; padding: 0 3px; line-height: 16px; }
  .char-tabs { flex: 1 1 0; height: 40px; overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; }
  .char-tabs::-webkit-scrollbar { display: none; }
  .char-tab-row { flex: none; }
  .char-tab-row:has(.is-shown) { order: -1; }
  .char-tab { height: 40px; min-width: var(--tap); max-width: 110px; padding: 0 6px; justify-content: center; }
  .char-tab:not(.is-shown) .char-tab-main, .char-tab-doing, .char-bars { display: none; }
  @container char-strip (max-width: 150px) { .char-tabs { display: none; } }
  /* No room for a tab: the press to every hero names the one on screen, over its word (a player at 667 px could not see whose bar it was). */
  @container char-strip (max-width: 150px) {
    .char-tool-now { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 18px; color: var(--gold-2); }
    .char-tool-short { display: block; line-height: 18px; font-weight: 400; }
  }
}
/* The connection's one line (src/net/connection.js): solid, over everything, taking no press. */
.conn-line { position: fixed; top: 56px; left: 50%; z-index: 70; transform: translateX(-50%); box-sizing: border-box; width: max-content; max-width: calc(100vw - 24px); margin: 0; padding: 2px 10px 2px 14px; pointer-events: none;
  background: var(--bg-2); border: 6px solid transparent; border-image: url('../../assets/ui/steel-frame-thin.png') 3 / 6px stretch; image-rendering: pixelated; box-shadow: inset 4px 0 0 var(--gold);
  font-family: var(--f-ui); font-size: var(--t-small); color: var(--ink); }
.conn-line[hidden] { display: none; }
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .conn-line { top: 104px; font-size: var(--t-micro); }
}
/* In a hunt the top bar carries the ground's name and clock, so the pane's own
   title row would only repeat it and cost the stage a line. Keyed on the SCENE (world-boot.js paintChrome), never on
   the bar alone: the bar stays up in town after a hunt ends ("Last hunt: ... Summary") and took the Town / Home
   buttons with it (Andy 2026-11-01: no way back out of the house). */
.app.is-game #panel-world[data-scene="hunt"]:has(.ht-bar) .world-chrome { display: none; }

/* THE CREATION STEP (src/app/hero-create.js), in the account card: the hero in a sunk mirror on the left (drawn at
   x4, standing on the pixel ground shadow at the same x4), its name and four colour strips beside it, then How you
   fight; the foot holds the way back and Enter town. */
.auth-card.is-create { width: min(60rem, 100%); }
/* The step fits the screen it opens on: the crest is on the screens before it (newcomer panel 2026-11-01: Enter town at y=985 at 1366x768). */
.auth:has(.auth-card.is-create) .auth-brand { display: none; }
.hero-body { display: flex; gap: 18px; align-items: flex-start; }
/* The real hero in the colors being picked: the outfit it starts in, large, and three more on the same ground, so every pick shows on something. */
.hero-look { flex: none; width: 192px; display: flex; flex-direction: column; gap: 4px; }
.hero-preview { display: block; width: 192px; height: 192px; image-rendering: pixelated;
  background: url('../../assets/ui/ground-shadow.png') 50% calc(100% - 8px) / 96px 20px no-repeat, var(--bg-2); box-shadow: var(--steel-well); }
.hero-others { display: flex; justify-content: space-between; }
.hero-other { display: block; width: 64px; height: 64px; image-rendering: pixelated; background: var(--bg-2); box-shadow: var(--steel-well); }
.hero-note { margin: 0; font-size: var(--t-micro); color: var(--ink-2); }
.hero-colors { display: flex; flex-direction: column; gap: 8px; }
.hero-pick { display: none; }
.hero-form { flex: none; min-width: 16rem; display: flex; flex-direction: column; gap: 8px; }
.hero-region { margin: 0; padding: 0; border: 0; min-width: 0; }
.hero-region legend { padding: 0 0 3px; font-family: var(--f-label); font-weight: 700; font-size: var(--t-micro); letter-spacing: .04em; color: var(--ink-2); }
/* A colour strip: the swatches sunk in one well (a slot row is sunk, never framed), the picked one ringed in gold. */
.hero-dyes { display: grid; grid-template-columns: repeat(16, 18px); gap: 2px; width: max-content; padding: 4px; background: var(--bg-0); box-shadow: var(--steel-well); }
.hero-dye { width: 18px; height: 18px; padding: 0; border: 0; border-radius: 0; background: var(--hero-dye); cursor: pointer; }
.hero-dye[aria-pressed="true"] { outline: 2px solid var(--gold-2); outline-offset: 1px; }
.hero-dye:focus-visible { outline: 2px solid var(--aqua-2); outline-offset: 1px; }
/* "How you fight" (Tyler 2026-10-22): no class to pick, the weapon is the style. A column beside the form behind a
   steel rule, under a Forged Steel section head (.hs-sub). */
.hero-how { flex: 1; min-width: 14rem; border-left: 2px solid var(--steel-sep); padding-left: 16px; }
.hero-how-title { margin: 0 0 6px; }
.hero-how-lead { margin: 0 0 8px; font-size: var(--t-micro); color: var(--ink); line-height: 1.4; }
.hero-how-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-size: var(--t-micro); color: var(--ink-2); line-height: 1.35; }
.hero-how-list b { color: var(--ink); }
.hero-how-uses { color: var(--ink-3); }
.hero-how-more { display: none; }
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .hero-body { gap: 12px; }
  .hero-form { gap: 4px; }
  .hero-dyes { grid-template-columns: repeat(16, 16px); padding: 3px; }
  .hero-dye { width: 16px; height: 16px; }
  /* Each strip's word beside it, not over it: the card's foot (Enter town) ends on a 375 px screen (panel 2026-11-01: 9 px off). */
  .hero-region legend { float: left; width: 38px; padding: 3px 0 0; }
  /* The phone shows How you fight too (playtest 2026-10-29: a phone player never met the five ways to fight). The step takes
     the screen's height, less the card's own 136 px and the page's 6, and scrolls as one: the name and the lead at the left, all
     five ways beside them (phone panel v0.2.83: cut after the bow, nothing said there was more). A screen still too short
     scrolls, and its cue says so (hero-create.js). A refusal's line takes its room from here, so Enter town stays on screen.
     The lead's word on slots waits for the Help page. */
  .hero-body { position: relative; align-items: flex-start; height: min(calc(100vh - 142px), 280px); overflow-y: auto; overscroll-behavior: contain; }
  .auth-card.is-create .auth-message:empty { display: none; }
  .auth-card.is-create:has(.auth-message:not(:empty)) .hero-body { height: min(calc(100vh - 176px), 246px); }
  .hero-how { min-width: 0; min-height: 100%; padding-left: 12px; }
  .hero-form { flex: none; width: 200px; min-width: 0; }
  .hero-form .auth-field { flex-direction: row; align-items: center; gap: 8px; }
  .hero-form .hero-name { flex: 1; min-width: 0; }
  .hero-how-lead { position: absolute; left: 0; top: 42px; width: 200px; margin: 0; line-height: 1.3; }
  .hero-how-slots { display: none; }
  .hero-how-list { gap: 3px; line-height: 1.3; }
  .hero-how-lead, .hero-how-list { font-size-adjust: var(--f-ui-aspect); }
  .hero-how-more:not([hidden]) { display: block; position: sticky; bottom: 0; margin: 2px 0 0; background: var(--bg-1); font-size: var(--t-micro); font-weight: 700; color: var(--gold-2); text-align: right; }
  /* Beside this card the crest leaves a 667 px phone 455 px: Enter town and How you fight ran off the right edge (played
     2026-10-31). The crest stays on sign-in; this step uses the room. */
  .auth:has(.auth-card.is-create) { gap: 0; padding: 2px 4px; }
  /* A phone's step shows one thing at a time: How you fight first, as it always has; Pick colors swaps it for the hero and its strips. */
  .hero-look, .hero-colors { display: none; }
  .auth-card.is-create { position: relative; }
  .hero-pick { display: block; position: absolute; top: 8px; right: 16px; }
  .auth-card.is-picking .hero-how { display: none; }
  .auth-card.is-picking .hero-look { display: flex; width: 128px; }
  .auth-card.is-picking .hero-preview { width: 128px; height: 128px; }
  .auth-card.is-picking .hero-others, .auth-card.is-picking .hero-note { display: none; }
  .auth-card.is-picking .hero-form { width: auto; }
  .auth-card.is-picking .hero-colors { display: flex; gap: 2px; }
}

/* THE LOADING SHELL (play.html .boot-shell; src/platform/load-shell.js): the crest, one line and a thin bar, in the middle
   of the page until the first screen takes over. */
.boot-shell { position: fixed; inset: 0; pointer-events: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 16px; }
.boot-shell-line { margin: 0; font-family: var(--f-ui); font-size: 15px; color: var(--ink); text-align: center; }
.boot-shell-bar { width: min(280px, 70vw); height: 4px; background: var(--line); }
.boot-shell-fill { display: block; width: 0; height: 100%; background: var(--gold); transition: width .2s linear; }
/* The press after the page's own tries: drawn with no image, since the images may be what is not arriving (the gold plate's text alone is dark on dark). */
.boot-shell-again { pointer-events: auto; min-height: 44px; padding: 0 24px; border: 0; background: var(--gold); color: var(--bg-0); font-family: var(--f-ui); font-size: var(--t-body); font-weight: 700; cursor: pointer; }
.boot-shell-again:hover { background: var(--gold-2); }
.boot-shell-again:focus-visible { outline: 2px solid var(--aqua-2); outline-offset: 2px; }
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .boot-shell .auth-crest { width: 78px; height: 96px; }
}
@media (prefers-reduced-motion: reduce) { .boot-shell-fill { transition: none; } }

/* A PHONE HELD UPRIGHT (play.html .turn-phone; QA 2026-10-24: in portrait the cards ran off the right edge and half
   the icon row and the bar were off screen). Phones are landscape-only (CLAUDE.md §1): a touch phone held upright
   sees the crest and ONE steel card (the account screens' pieces, by their classes) over everything, and nothing
   under it takes a press. The query asks for a touch-only screen at most 600 px wide, upright: a desktop window,
   however narrow, and a tablet either way up never see it. */
.turn-phone {
  display: none; position: fixed; inset: 0; z-index: 100;
  flex-direction: column; align-items: center; justify-content: center; gap: 16px;
  padding: 24px; box-sizing: border-box; overflow: auto;
  background: var(--bg-0);
}
.turn-phone-card { text-align: center; }
.turn-phone-card .auth-title { justify-content: center; }
@media (orientation: portrait) and (max-width: 600px) and (hover: none) and (pointer: coarse) {
  .turn-phone { display: flex; }
}

/* ?debug=live (src/app/live-overlay.js): a read-only corner over everything, never in the way of a press. */
.live-overlay { position: fixed; left: 8px; bottom: 8px; z-index: 60; pointer-events: none; margin: 0; padding: 6px 8px;
  background: var(--world-hud-bg); color: var(--ink); font-family: var(--f-ui); font-size: var(--t-micro); line-height: 1.3;
  font-variant-numeric: tabular-nums; }
.live-overlay p { margin: 0; white-space: nowrap; }

/* A NEW RELEASE (src/app/new-version.js): one calm line above the app, IN FLOW, so it pushes the
   game down and never covers the action bar or a window. Later hides it until the next check.
   The app is the box of the screen layer (.hs-screen, the launcher row), so the row comes down with it and never lies over Reload. */
.client-page.has-new-version { display: flex; flex-direction: column; height: 100vh; }
.client-page.has-new-version .app { position: relative; flex: 1; min-height: 0; height: auto; }
.client-page.has-new-version .app.is-auth { overflow: auto; }
.new-version {
  flex: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px 14px;
  padding: 6px 12px;
  background: var(--bg-1); border-bottom: 1px solid var(--line-strong);
  color: var(--ink); font-family: var(--f-ui); font-size: var(--t-small); line-height: 1.3;
}
.new-version-line { margin: 0; }
.new-version-reload {
  font-family: var(--f-ui); font-weight: 700; font-size: var(--t-small);
  min-height: 32px; padding: 0 14px;
  color: var(--bg-0); background: var(--gold);
  border: 0; border-radius: var(--r-sm); cursor: pointer;
}
.new-version-reload:hover { background: var(--gold-2); }
.new-version-later { font-family: var(--f-ui); font-size: var(--t-small); color: var(--ink-2); background: none; border: 0; padding: 2px 4px; cursor: pointer; }
.new-version-later:hover { color: var(--ink); }
.new-version-reload:focus-visible, .new-version-later:focus-visible { outline: 2px solid var(--aqua-2); outline-offset: 2px; }
@media (max-width: 540px), (max-height: 540px) and (max-width: 1024px) {
  .new-version { padding: 2px 8px; gap: 2px 10px; font-size: var(--t-micro); }
  .new-version-reload { min-height: 28px; font-size: var(--t-micro); }
  .new-version-later { font-size: var(--t-micro); }
}
