/* The welcome page: the bar fills the frame, and the interface sits over it the Final Fantasy
   way (TDD.md §11): the location title top left, key-glyph commands, and a dialogue box at the
   bottom, all in a coder's terminal font (§14, decision 38). */
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
:root {
  --text: #f2f2f2;
  --candle: #ffb35a;
  --candle-core: #ffe2a0;
  --terminal: #9be39b;
  --box: rgb(8 14 30 / 88%);
  --line: rgb(170 195 255 / 45%);
  --shadow: 0 1px 3px rgb(0 0 0 / 90%), 0 0 8px rgb(0 0 0 / 60%);
  --mono: "JetBrains Mono", ui-monospace, "Cascadia Code", Menlo, Consolas, monospace;
  /* The panels' and menus' one palette (TDD.md §11): every panel uses these, links.css included. */
  --muted: rgb(242 242 242 / 72%);
  --panel-border: rgb(210 214 222 / 55%);
  --panel-radius: 8px;
  --panel-glow: 0 6px 22px rgb(0 0 0 / 70%), 0 0 30px rgb(255 179 90 / 14%);
  --plate: linear-gradient(#e4c27a, #b48a3e);
  --plate-ink: #1f1810;
  --control-bg: rgb(0 0 0 / 40%);
  --control-border: var(--line);
  --control-radius: 6px;
  --pressed-bg: rgb(255 179 90 / 16%);
  --cool: #9cc0ff;
  --cool-bg: rgb(156 192 255 / 14%);
  --card-bg: rgb(255 255 255 / 5%);
  --card-border: rgb(170 195 255 / 22%);
  --card-radius: 6px;
  --house-bg: rgb(255 179 90 / 9%);
  --members-bg: rgb(56 47 39 / 70%);
  --well: rgb(0 0 0 / 45%);
  --lightbox-bg: rgb(5 9 20 / 97%);
  /* On a phone a panel covers the title and commands: nearly opaque, so nothing reads through. */
  --box-phone: rgb(8 14 30 / 97%);
  /* A playing card's face, the one light surface in a panel. */
  --card-face: #f5ecd7;
  --card-face-edge: #a8987c;
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: #000000; }
body { color: var(--text); font: 400 16px/1.6 var(--mono); text-shadow: var(--shadow); }

/* The bar: the renderer's canvas, fading in over black when its first frame is drawn; a capture of
   the room (the poster) only where the room can't be drawn (`.still`). */
/* Clipped, not hidden: a name marker past the screen's edge widens what the scene holds, and a
   hidden overflow is still a scroller, so focusing a marker or a panel's control would slide the
   whole room and its panel sideways. A clip is no scroller at all. */
.scene { position: relative; width: 100%; height: 100vh; height: 100svh; min-height: 520px; overflow: hidden; overflow: clip; }
.scene canvas, .scene .view, .scene .poster { position: absolute; inset: 0; width: 100%; height: 100%; }
.scene .poster { object-fit: cover; display: none; }
.scene.still .poster { display: block; }
/* Touches belong to the room (drag and pinch), not to the browser's scrolling and zooming. */
.scene canvas { touch-action: none; }
@media (prefers-reduced-motion: no-preference) {
  .scene.live canvas { animation: fade-in 0.9s ease-out; }
  @keyframes fade-in { from { opacity: 0; } }
}

/* The location title, with its thin underline flourish, and the subtitle line. */
.location { position: absolute; top: 20px; left: 24px; z-index: 2; }
.location h1 {
  margin: 0;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 0 80px 4px 0;
  display: inline-block;
  background: linear-gradient(90deg, rgb(242 242 242 / 85%) 60%, transparent) bottom left / 100% 1px no-repeat;
}
.location p { margin: 4px 0 0 22px; font-size: 0.95rem; opacity: 0.9; }

/* Commands as small rounded-square key glyphs with labels. */
.commands {
  position: absolute;
  left: 24px;
  top: 42%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.commands a, .commands .sound {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
  font-size: 1.05rem;
  min-height: 44px;
}
.commands :is(a, .sound):is(:hover, :focus-visible) span { color: var(--candle-core); }
.commands span { white-space: nowrap; }
kbd {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 1.5px solid var(--text);
  border-radius: 6px;
  font: 700 0.8rem var(--mono);
  box-shadow: 0 1px 3px rgb(0 0 0 / 80%);
}

/* The dialogue box: a dark band fading at its ends, the speaker's name over a fine line. */
.dialogue {
  position: absolute;
  left: 50%;
  bottom: 3.5%;
  z-index: 2;
  transform: translateX(-50%);
  width: min(900px, 92%);
  padding: 14px 64px 22px;
  background: linear-gradient(90deg, transparent, var(--box) 9%, var(--box) 91%, transparent);
}
.dialogue.paged { cursor: pointer; }
.dialogue a { color: var(--candle-core); }
.speaker {
  margin: 0 0 8px;
  font-weight: 700;
  font-size: 1.05rem;
  padding-bottom: 6px;
  background: linear-gradient(90deg, var(--line), rgb(170 195 255 / 25%) 70%, transparent) bottom left / 100% 1px no-repeat;
}
.pages p { margin: 0 0 8px; min-height: 3.2em; font-size: 1.02rem; }
.dialogue:not(.paged) .pages p { min-height: 0; }
.command {
  display: block;
  margin: 6px 0;
  color: var(--terminal);
  text-decoration: none;
  font-weight: 700;
}
.command:hover, .command:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
a:focus-visible { outline: 2px solid var(--candle); outline-offset: 3px; border-radius: 4px; }
.next {
  position: absolute;
  right: 40px;
  bottom: 12px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.8rem;
  text-shadow: inherit;
  cursor: pointer;
  opacity: 0;
}
.next:focus-visible { opacity: 0.9; outline: 2px solid var(--candle); outline-offset: 3px; }
.dialogue:not(.paged) .next { display: none; }
.dialogue.paged.ready:not(.last) .next { opacity: 0.9; }
/* The last page waits like a terminal prompt, with a blinking block cursor. */
.dialogue.paged.ready.last .pages p:not([hidden])::after {
  content: "█";
  margin-left: 4px;
  color: var(--terminal);
}
@media (prefers-reduced-motion: no-preference) {
  .dialogue.paged.ready:not(.last) .next { animation: bob 1.2s ease-in-out infinite; }
  .dialogue.paged.ready.last .pages p:not([hidden])::after { animation: blink 1.1s steps(1) infinite; }
  @keyframes bob { 50% { transform: translateY(3px); } }
  @keyframes blink { 50% { opacity: 0; } }
}

/* Phones: the box spans the width along the bottom. */
@media (max-width: 700px) {
  .location { top: 14px; left: 16px; }
  .location h1 { font-size: 1.6rem; padding-right: 48px; }
  .location p { font-size: 0.8rem; margin-left: 12px; }
  .commands { top: 76px; left: 16px; right: 16px; flex-flow: row wrap; gap: 0 16px; }
  .dialogue { width: 100%; padding: 12px 22px 20px; bottom: 0; background: var(--box); }
  .pages p { font-size: 0.92rem; min-height: 4.8em; }
  .next { right: 18px; }
}

/* Short screens (a phone on its side): the scene fits the screen, so the box is always in reach. */
@media (max-height: 520px) {
  .scene { min-height: 0; }
  .commands { top: 76px; }
  .dialogue { bottom: 0; padding: 6px 22px 10px; }
  .speaker { margin-bottom: 4px; padding-bottom: 2px; }
  .pages p { font-size: 0.85rem; line-height: 1.4; min-height: 4.2em; margin: 0; }
  .next { bottom: 4px; }
}

/* The Sound toggle sits with the commands, as a key glyph like the others. */
.commands .sound {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--mono);
  text-shadow: var(--shadow);
  cursor: pointer;
}
.commands .sound[aria-pressed="true"] kbd { background: rgb(242 242 242 / 18%); }

/* Phones: a one-time hint that the room can be dragged around. */
.hint {
  position: absolute;
  left: 50%;
  top: 38%;
  z-index: 2;
  transform: translateX(-50%);
  margin: 0;
  padding: 6px 14px;
  border-radius: 999px;
  background: rgb(8 14 30 / 70%);
  font-size: 0.85rem;
  opacity: 0;
  transition: opacity 0.6s;
  pointer-events: none;
}
.hint.shown { opacity: 0.9; }

/* The room: name markers, which the renderer keeps over their figures each frame, each speaker's bubble over their head, the house's
   quiet notice, and the box to say something in. */
.marker {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  padding: 0 6px;
  border-radius: 4px;
  background: rgb(8 14 30 / 70%);
  font-size: 0.8rem;
  white-space: nowrap;
  pointer-events: none;
}
.scene:not(.live) .marker { display: none; }
/* A speech bubble (TDD.md §11): warm parchment in candlelight, a soft outline and a small
   tail, hung `--rise` over the speaker's spot (a sprite's head, from the renderer) or else just
   over their name, `--lift` higher when a neighbour's would cover it and `--shift` aside at a
   screen's edge, its tail still over the speaker. Its lines come wrapped (`ui/bubbles.ts`). */
.bubble {
  --paper: #f5ecd7;
  --ink: #2e241a;
  --edge: #a8987c;
  position: absolute;
  left: 50%;
  bottom: calc(max(var(--rise, 0px), 100%) + var(--lift, 0px) + 8px);
  transform: translateX(calc(var(--shift, 0px) - 50%));
  width: max-content;
  padding: 5px 10px 6px;
  border: 1px solid var(--edge);
  border-radius: 12px;
  background: var(--paper);
  color: var(--ink);
  font-size: 0.8rem;
  line-height: 1.35;
  text-shadow: none;
  white-space: pre;
  box-shadow: 0 2px 6px rgb(0 0 0 / 50%), 0 0 16px rgb(255 179 90 / 22%);
  transition: opacity 0.7s;
}
.bubble::after {
  content: "";
  position: absolute;
  left: clamp(14px, calc(50% - var(--shift, 0px)), calc(100% - 14px));
  bottom: -5px;
  width: 8px;
  height: 8px;
  border: solid var(--edge);
  border-width: 0 1px 1px 0;
  background: var(--paper);
  transform: translateX(-50%) rotate(45deg);
}
.bubble b { display: block; font-size: 0.7rem; color: #7a5528; }
/* More pages follow, as the dialogue box's ▼ says. */
.bubble.more::before { content: "▼"; position: absolute; right: 5px; bottom: 0; font-size: 0.5rem; opacity: 0.55; }
/* A whisper: smaller and dimmer, seen only by the two. */
.bubble.hushed { --paper: #ddd4c2; --edge: #8f846f; font-size: 0.7rem; font-style: italic; opacity: 0.82; }
.bubble.gone { opacity: 0; }
/* The house's own words: one quiet notice near the top, under the title and commands, fading. */
.notice {
  position: absolute;
  top: 128px;
  left: 50%;
  z-index: 2;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 32px);
  margin: 0;
  padding: 3px 12px;
  border-radius: 999px;
  background: rgb(8 14 30 / 55%);
  color: var(--candle-core);
  font-size: 0.78rem;
  text-align: center;
  pointer-events: none;
  transition: opacity 0.7s;
}
.notice.gone { opacity: 0; }
/* The newest line, for a screen reader alone. */
.heard { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); margin: 0; }
/* The door and the say box live in the dialogue box (TDD §11). The door waits for the welcome's
   last page, or shows at once to a visitor whose key this browser keeps; once in (`.in`), the
   welcome gives way to the say box. */
.dialogue [hidden] { display: none; }
.dialogue.paged:not(.ready.last, .known) .door { display: none; }
.dialogue.in { cursor: auto; }
.dialogue.in :is(.speaker, .pages, .next) { display: none; }
.dialogue .status { margin: 0 0 8px; color: var(--candle); }
.dialogue .status:empty { display: none; }
.door, .talk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-top: 4px; }
.door label { display: flex; flex: 1 1 100%; align-items: center; gap: 10px; }
.dialogue input { flex: 1; min-width: 0; }
.dialogue :is(input, button:not(.next)) {
  min-height: 40px;
  padding: 6px 12px;
  border: 1px solid var(--control-border);
  border-radius: var(--control-radius);
  background: var(--control-bg);
  color: inherit;
  font: inherit;
  text-shadow: inherit;
}
.dialogue ::placeholder { color: var(--muted); opacity: 1; }
.door button:not(.aside) { border-color: var(--candle); color: var(--candle-core); font-weight: 700; cursor: pointer; }
/* The small options beside it: a key to give, or one to forget. */
.dialogue button.aside { padding: 6px 2px; border: 0; background: none; font-size: 0.85rem; opacity: 0.85; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.dialogue :is(input, button:not(.next)):focus-visible { outline: 2px solid var(--candle); outline-offset: 2px; }
@media (max-width: 700px) {
  .dialogue.in { padding: 10px 16px 12px; }
  .dialogue .status { margin-bottom: 6px; font-size: 0.85rem; }
}
/* Words to one person (Tell, Whisper to): their name before the box, and a way back to the room. */
.talk .to { display: inline-flex; align-items: center; gap: 4px; color: var(--candle-core); font-size: 0.85rem; }
.dialogue .talk .to button { min-height: 32px; padding: 0 8px; border: 0; background: none; cursor: pointer; }
.dialogue .talk .to[hidden] { display: none; }

/* A name is a button by keyboard (the pointer passes through to the room). */
.marker:focus-visible { outline: 2px solid var(--candle); outline-offset: 2px; }
/* The menu on a person (TDD.md §11): a panel, translucent dark with a thin rounded border,
   their name over a fine line, and a ▸ beside the choice in hand, as the dialogue's menus have. */
.menu {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  min-width: 10.5rem;
  padding: 6px 6px 8px;
  border: 1px solid var(--panel-border);
  border-radius: var(--panel-radius);
  background: var(--box);
  box-shadow: var(--panel-glow);
}
.menu[hidden] { display: none; }
.menu p {
  margin: 0 6px 4px;
  padding: 2px 0 5px;
  font-weight: 700;
  font-size: 0.9rem;
  background: linear-gradient(90deg, var(--line), rgb(170 195 255 / 25%) 70%, transparent) bottom left / 100% 1px no-repeat;
}
.menu button {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  min-height: 36px;
  padding: 4px 8px 4px 22px;
  border: 0;
  border-radius: 4px;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.9rem;
  text-align: left;
  text-shadow: inherit;
  cursor: pointer;
  position: relative;
}
.menu button:is(:hover, :focus-visible) { color: var(--candle-core); outline: none; }
.menu button:is(:hover, :focus-visible)::before { content: "▸"; position: absolute; left: 7px; }
/* Phones: large tap targets (TDD.md §11). */
@media (pointer: coarse) { .menu button { min-height: 44px; } }

/* A page of plain reading (the proof of reserve, GDD §20): the same room behind, dimmed, and one
   box of text over it that scrolls with the page. */
.backdrop { position: fixed; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.3; }
.sheet { position: relative; max-width: 860px; margin: 0 auto; padding: 20px 24px 48px; }
.sheet .location { position: static; margin-bottom: 28px; }
.ledger { padding: 16px 32px 20px; background: var(--box); }
.ledger h2 { font-size: 1.05rem; }
.ledger p { margin: 0 0 12px; }
.ledger a { color: var(--candle-core); }
.ledger .notice { padding-left: 12px; border-left: 3px solid var(--candle); color: var(--candle-core); }
.ledger .status { color: var(--candle); font-weight: 700; }
.ledger .small { font-size: 0.88rem; opacity: 0.9; }
.ledger dl { margin: 18px 0; }
.ledger dl div {
  display: grid;
  grid-template-columns: 14rem 1fr;
  gap: 4px 16px;
  padding: 9px 0;
  background: linear-gradient(90deg, var(--line), rgb(170 195 255 / 15%) 70%, transparent) top left / 100% 1px no-repeat;
}
.ledger dt { opacity: 0.8; }
.ledger dd { margin: 0; font-weight: 700; }
.ledger dd a { font-weight: 400; font-size: 0.88rem; }
/* Until the server has named the Safe's page on the chain, the link stays hidden. */
.ledger dd a:not([hidden]) { display: block; }
.ledger .address { overflow-wrap: anywhere; }
/* Green only for a reserve that covers the books now: short, or a reading grown old, is amber. */
.ledger dd[data-standing="covered"] { color: var(--terminal); }
.ledger dd:is([data-standing="short"], [data-standing="breach"], [data-standing="stale"]) { color: var(--candle); }
@media (max-width: 700px) {
  .sheet { padding: 14px 0 0; }
  .sheet .location { margin: 0 16px 18px; }
  .ledger { padding: 14px 22px 20px; }
  .ledger dl div { grid-template-columns: 1fr; }
}

/* The room's panels, one family (TDD.md §11): the notice board, sign-up, the bar's menu, the poker
   table (`ui/panel.ts`), the canvas and the Jukebox (`links.css`), each translucent dark with a thin
   rounded border under a brass plate naming it, the page's font and its candle accent; their body
   scrolls, and the server's words show under it. Every colour, border and radius is a token above. */
:is(.panel, .board, .links) {
  position: absolute;
  top: 84px;
  left: 50%;
  z-index: 3;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  width: min(560px, calc(100% - 32px));
  max-height: calc(100% - 230px);
  padding: 10px 14px 12px;
  border: 1px solid var(--panel-border);
  border-radius: var(--panel-radius);
  background: var(--box);
  box-shadow: var(--panel-glow);
  font-size: 0.88rem;
}
:is(.panel, .board, .links) header { display: flex; align-items: center; justify-content: center; position: relative; min-height: 28px; margin-bottom: 8px; }
/* The brass plate over each panel. */
:is(.panel, .board, .links) h2 {
  margin: 0;
  padding: 1px 14px;
  border-radius: 3px;
  background: var(--plate);
  color: var(--plate-ink);
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-shadow: none;
}
:is(.panel, .board, .links) .shut {
  position: absolute;
  right: -6px;
  top: -6px;
  min-width: 40px;
  min-height: 40px;
  border: 0;
  background: none;
  color: var(--text);
  font: 700 1.2rem var(--mono);
  cursor: pointer;
}
:is(.panel, .board, .links) .status { margin: 0 0 6px; color: var(--candle-core); }
:is(.panel, .board, .links) .status:empty { display: none; }
/* The controls: dark, a fine border, the candle's for the one that acts. */
:is(.panel, .board, .links) :is(button, input, select, textarea) { font: inherit; color: inherit; text-shadow: inherit; }
:is(.panel, .board, .links) :is(button:not(.shut, .back, .up, .down, .play, .zoom, .talk), select, textarea, input:not([type="checkbox"], [type="range"], [type="file"])) {
  min-height: 36px;
  padding: 4px 10px;
  border: 1px solid var(--control-border);
  border-radius: var(--control-radius);
  background: var(--control-bg);
}
:is(.panel, .board, .links) textarea { resize: none; line-height: 1.4; }
:is(.panel, .board, .links) ::placeholder { color: var(--muted); opacity: 1; }
:is(.panel, .board, .links) select option { background: #0b1222; }
:is(.panel, .board, .links) button:not(.shut) { cursor: pointer; }
:is(.panel, .board, .links) button:disabled { opacity: 0.45; cursor: default; }
:is(.panel, .board, .links) :is(button.go, .pin button, form.share > button, .more, .older):not(:disabled) { border-color: var(--candle); color: var(--candle-core); font-weight: 700; }
:is(.panel, .board, .links) [aria-pressed="true"]:not(.up, .down) { border-color: var(--candle); background: var(--pressed-bg); color: var(--candle-core); }
:is(.panel, .board, .links) :is(button, input, select, textarea, a):focus-visible { outline: 2px solid var(--candle); outline-offset: 2px; }
:is(.panel, .board, .links) a { color: var(--candle-core); }
:is(.panel, .board, .links) .members { margin: 0; padding: 6px 10px; border-radius: var(--control-radius); background: var(--members-bg); text-align: center; }
/* A card: a note, a piece, a link or a comment, a little lighter than the panel, its maker's
   name in the muted line over its words. */
:is(.board, .links) :is(.paper, .card, .comment, .empty, .write) {
  position: relative;
  margin: 0 0 8px;
  padding: 8px 10px;
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  background: var(--card-bg);
}
:is(.board, .links) .empty { color: var(--muted); font-style: italic; }
:is(.board, .links) .by { margin: 0 0 2px; font-size: 0.72rem; font-weight: 700; color: var(--muted); }
:is(.board, .links) :is(.words, .caption) { margin: 0; font-size: 0.84rem; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }
:is(.board .down, .links .talk) {
  margin-top: 4px;
  padding: 2px 0;
  border: 0;
  background: none;
  color: var(--candle);
  font-size: 0.74rem;
  text-decoration: underline;
  text-underline-offset: 2px;
}
@media (pointer: coarse) {
  :is(.panel, .board, .links) :is(button:not(.shut, .back, .up, .down, .play, .zoom, .talk), select, input:not([type="checkbox"], [type="range"], [type="file"])) { min-height: 44px; }
}
@media (max-width: 700px) {
  :is(.panel, .board, .links) { top: 64px; max-height: calc(100% - 200px); padding: 8px 10px 10px; background: var(--box-phone); }
}

/* The notice board (WLD-7): the house's notice first, warmed by the candle's edge, then the newest
   notes, each under a brass pin. */
.board .papers { flex: 1 1 auto; overflow-y: auto; margin: 0; padding: 6px 2px 0; list-style: none; }
.board .paper { padding-top: 10px; }
.board .paper::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 50%;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #f3d68e, #9a7432);
  box-shadow: 0 1px 2px rgb(0 0 0 / 60%);
}
.board .paper.house { border-left: 3px solid var(--candle); background: var(--house-bg); }
.board .older { align-self: center; margin: 2px 0 8px; }
.board .pin { display: flex; gap: 8px; align-items: stretch; }
.board .pin textarea { flex: 1; min-width: 0; }
/* Last among the board's rules, so a hidden part stays hidden over its own display. */
.board[hidden], .board [hidden] { display: none; }

/* The other panels' own parts (`ui/panel.ts`): a body that scrolls, and a field's label beside it. */
.panel .body { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding: 2px; }
.panel p { margin: 0 0 8px; }
.panel .status { margin: 8px 0 0; }
.panel .members .join { margin-left: 6px; border-color: var(--candle); color: var(--candle-core); font-weight: 700; }
.panel .field { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; }
.panel .field :is(input, select) { flex: 1; min-width: 0; }
/* Sign-up: the handle, three ticks of the visitor's own, the sum's progress, then the key and code once. */
.join .tick { display: flex; align-items: baseline; gap: 8px; margin: 0 0 8px; line-height: 1.4; }
.join .tick input { flex: none; width: 18px; height: 18px; accent-color: var(--candle); }
.join .signup > button { margin-top: 4px; }
.join progress { width: 100%; height: 10px; accent-color: var(--candle); }
.join .secret { display: flex; align-items: flex-end; gap: 8px; margin: 0 0 10px; }
.join .secret label { display: flex; flex-direction: column; flex: 1; min-width: 0; gap: 2px; font-size: 0.8rem; }
.join .secret input { width: 100%; font-size: 0.78rem; color: var(--terminal); }
.join .warning { padding: 6px 10px; border-left: 3px solid var(--candle); color: var(--candle-core); }
/* The bar's menu: each drink, its price, and Order for a member; Halloween's green that night. */
.bar .balance { color: var(--candle-core); font-weight: 700; }
.bar .drinks { margin: 0; padding: 0; list-style: none; }
.bar .drink { display: flex; align-items: center; gap: 10px; padding: 5px 0; border-bottom: 1px solid var(--card-border); }
.bar .drink .name { flex: 1; }
.bar .drink .price { opacity: 0.85; white-space: nowrap; }
.bar .drink.halloween .name { color: #8fe08f; }
.bar .drink.halloween .name::after { content: " · Halloween"; font-size: 0.72rem; opacity: 0.8; }
.bar .members { margin-top: 10px; }
/* The poker panel: the lobby's rows, then the table: the board and your cards as cards, the seats, the moves. */
.poker h3 { margin: 10px 0 6px; font-size: 0.8rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--candle); }
.poker .row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 6px 0; border-bottom: 1px solid var(--card-border); }
.poker .row .said { flex: 1 1 14rem; min-width: 0; }
.poker .row p { margin: 0; }
.poker .row .name { font-weight: 700; }
.poker .row .line { font-size: 0.8rem; opacity: 0.9; }
.poker .acts { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.poker input.amount { width: 6.5rem; }
.poker .head { font-weight: 700; }
.poker .card {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6rem;
  height: 3.5rem;
  border: 1px solid var(--card-face-edge);
  border-radius: 5px;
  background: var(--card-face);
  color: #1d1d1d;
  font-weight: 700;
  font-size: 1rem;
  text-shadow: none;
}
.poker .card.red { color: #b3261e; }
.poker .card.empty { border-style: dashed; border-color: rgb(210 214 222 / 35%); background: rgb(0 0 0 / 25%); }
.poker .yours .card { width: 3.1rem; height: 4.2rem; font-size: 1.15rem; }
.poker .yours { display: flex; gap: 6px; }
/* At the table (decision 145): the room seen from above its poker table, the panel a strip at the
   foot of the screen, the seats' names, stacks and words hung over their figures (`ui/felt.ts`'s tags,
   placed by `renderer/index.ts`), the room's own words and names out of the way meanwhile. */
.poker.strip { top: auto; bottom: 10px; max-height: min(52%, 420px); width: min(640px, calc(100% - 24px)); padding: 4px 12px 8px; }
.poker.strip header { min-height: 24px; margin-bottom: 2px; }
.poker.strip .head { margin: 0 0 4px; font-size: 0.78rem; opacity: 0.9; }
/* Kept short: whose turn the clock says, the log and the way out on one line. */
.poker.strip .note { display: none; }
.poker.strip .table { display: flex; flex-wrap: wrap; align-items: center; column-gap: 12px; }
.poker.strip .table > * { flex: 1 1 100%; }
.poker.strip .table > :is(.log, .foot) { flex: 0 1 auto; margin: 0; }
.poker.strip .log { display: flex; flex-wrap: wrap; gap: 0 12px; }
.poker.strip .log details[open] { flex: 1 1 100%; }
.scene.at-table :is(.marker, .dialogue, .commands, .hint) { display: none; }
.seat-tags { position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: clip; }
.scene:not(.at-table) .seat-tags { display: none; }
.seat-tag { position: absolute; top: 0; left: 0; display: flex; flex-direction: column; align-items: center; gap: 2px; padding-bottom: 4px; font-size: 0.7rem; line-height: 1.2; white-space: nowrap; }
.seat-tag[hidden] { display: none; }
/* The front row's tags hang under their figures, the word under the name. */
.seat-tag.below { flex-direction: column-reverse; padding: 4px 0 0; }
.seat-tag.below .said::after { top: -4px; bottom: auto; transform: translateX(-50%) rotate(225deg); }
.seat-tag .plate { display: flex; gap: 6px; padding: 1px 6px; border: 1px solid var(--panel-border); border-radius: 4px; background: rgb(8 14 30 / 80%); }
.seat-tag .who { max-width: 6.5rem; overflow: hidden; text-overflow: ellipsis; }
.seat-tag .stack { color: var(--candle-core); font-weight: 700; }
.seat-tag.you .who { color: var(--candle-core); }
.seat-tag.turn .plate { border-color: var(--candle); box-shadow: 0 0 10px rgb(255 179 90 / 60%); }
.seat-tag.won .plate { border-color: var(--terminal); }
.seat-tag.out .plate { opacity: 0.6; }
/* A move's word as a small speech bubble over the figure, popping in as it is made. */
.seat-tag .said { position: relative; padding: 0 7px; border: 1px solid var(--card-face-edge); border-radius: 9px; background: var(--card-face); color: #1d1d1d; font-weight: 700; text-shadow: none; }
.seat-tag .said::after { content: ""; position: absolute; left: 50%; bottom: -4px; width: 6px; height: 6px; background: inherit; border: inherit; border-width: 0 1px 1px 0; transform: translateX(-50%) rotate(45deg); }
.seat-tag .said:empty { display: none; }
.seat-tag .said.fresh { animation: said 0.35s ease-out; }
.seat-tag.won .said { background: #d8f5d0; }
.seat-tag.pot .plate { color: var(--candle-core); font-weight: 700; }
@keyframes said { from { opacity: 0; transform: translateY(6px) scale(0.5); } }
@media (prefers-reduced-motion: reduce) { .seat-tag .said.fresh { animation: none; } }
/* The cards in the strip as the room paints them: its own pixel art, each texel two pixels. */
.poker .card.art { width: auto; height: auto; padding: 0; border: 0; background: none; box-shadow: 0 2px 4px rgb(0 0 0 / 60%); }
.poker .card.art canvas { position: static; display: block; width: 46px; height: 60px; image-rendering: pixelated; }
.poker .yours .card.art canvas { width: 69px; height: 90px; }
.poker .hand { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0 0 8px; }
.poker .hand .facts { display: flex; gap: 12px; margin: 0; color: var(--candle-core); }
.poker .hand .clock { margin: 0 0 0 auto; }
.poker .hand .clock:not(:empty)::before { content: "⌛ "; }
.poker .early { display: flex; gap: 16px; margin: 0 0 8px; }
.poker .early .pick { display: flex; align-items: center; gap: 6px; cursor: pointer; }
.poker .early input { accent-color: var(--candle); width: 18px; height: 18px; }
.poker .log { margin: 0 0 8px; }
.poker .log summary { cursor: pointer; color: var(--candle); font-size: 0.78rem; }
.poker .log ol { max-height: 7.5rem; overflow-y: auto; margin: 4px 0 0; padding-left: 1.3rem; font-size: 0.75rem; }
.poker .yours { position: relative; }
.poker .yours .folded { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(-12deg); padding: 1px 6px; border: 2px solid #ff8a7a; border-radius: 4px; background: rgb(20 8 8 / 85%); color: #ff8a7a; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
.poker .clock { color: var(--candle); }
.poker .clock:empty { display: none; }
.poker .clock.short { color: #ff8a7a; font-weight: 700; }
.poker .finish { color: var(--terminal); }
/* The last hand's result, a few seconds: who won, the hands shown and the board, small cards. */
.poker div.back { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0 0 8px; }
.poker div.back p { margin: 0; flex: 1 1 12rem; color: var(--candle-core); }
.poker .warn { color: #ff8a7a; font-size: 0.85rem; }
.poker .moves { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; }
.poker .sizing { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex: 1 1 100%; }
.poker .sizing input[type="range"] { flex: 1 1 8rem; accent-color: var(--candle); }
.poker .note { font-size: 0.78rem; opacity: 0.8; }
.poker .foot { display: flex; gap: 8px; }
@media (max-width: 700px) {
  .poker .card { width: 2.2rem; height: 3rem; font-size: 0.9rem; }
  .poker.strip { bottom: 0; width: 100%; border-radius: var(--panel-radius) var(--panel-radius) 0 0; max-height: 55%; }
  /* The brass plate gives its room to the table on a phone; the strip's × stays. */
  .poker.strip header { min-height: 0; margin: 0; }
  .poker.strip h2 { display: none; }
  .poker.strip .shut { top: -10px; right: -8px; }
  .poker .yours .card.art canvas { width: 46px; height: 60px; }
  .seat-tag { font-size: 0.64rem; }
  .seat-tag .who { max-width: 4.6rem; }
}
/* The small forms (`ui/forms.ts`): Report, Tip, Appeal and the guestbook, over the panel they came
   from, narrower, the thing reported quoted in a card. */
.panel.form { z-index: 4; width: min(400px, calc(100% - 32px)); }
.form .lead p:first-child:not(:only-child) { padding: 6px 10px; border: 1px solid var(--card-border); border-radius: var(--card-radius); background: var(--card-bg); white-space: pre-wrap; overflow-wrap: anywhere; }
.form form.send { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.form form.send textarea { flex: 1 1 100%; }
.form form.send input.amount { width: 7rem; }
.form .tick { display: flex; flex: 1 1 100%; align-items: baseline; gap: 8px; line-height: 1.4; }
.form .tick input { flex: none; width: 18px; height: 18px; accent-color: var(--candle); }
/* Your limits: each period's limit, what it has lost and when it starts again, then a break. */
.limits .limit { margin: 0 0 8px; padding: 0 0 6px; border-bottom: 1px solid var(--card-border); }
.limits .limit .field { margin-bottom: 2px; }
.limits .field input { max-width: 9rem; }
.limits .line { margin: 0; font-size: 0.78rem; color: var(--muted); }
.limits .cool { margin-top: 6px; }
.limits .warning { padding: 6px 10px; border-left: 3px solid var(--candle); color: var(--candle-core); }
.limits form.set > button { margin: 6px 8px 0 0; }
.poker button.limits { margin: 0 0 8px; }
/* Report and Tip beside the board's and the canvas's own small words. */
.board .down + .down, .links .talk + .talk { margin-left: 12px; }
/* Beside the say box: its own menu, and an appeal after a rest. */
.dialogue .talk button.more { min-width: 32px; text-decoration: none; font-size: 1.1rem; letter-spacing: 0.1em; }
.dialogue .status button.appeal { min-height: 0; margin-left: 10px; padding: 0 2px; color: var(--candle-core); }
/* Last among the panels' rules, so a hidden part stays hidden over its own display. */
.panel[hidden], .panel [hidden] { display: none; }
