/* Hotel Escape — interface styling.
   Elegant 1980s/90s grand-hotel Art Deco: charcoal-navy panels, ivory text, brass detailing,
   a warm serif for names/labels. Every class the game code and tests rely on is preserved;
   the look is layered on with tokens below. */
:root {
  --bg: #0f1119;
  --ink: #12141d;
  --panel: rgba(18, 21, 30, 0.92);
  --panel-solid: #141824;
  --scrim: rgba(8, 9, 14, 0.62);

  --ivory: #efe7d6;
  --ivory-dim: #cabfa8;
  --muted: #a89e8a;
  --brass: #c9a24e;
  --brass-bright: #e8ca80;
  --brass-dim: #8c7233;
  --line: rgba(201, 162, 78, 0.42);
  --line-soft: rgba(201, 162, 78, 0.16);
  --crimson: #cf4a40;
  --evil: #b46bff;          /* the Possession CARD's violet (its art); not the possessed guest's look */

  /* The possessed guest's own private look (panel, role card, card view): a dark plum-crimson plate
     with a thin crimson line inside the brass border, like the owner's reference. Only ever on the
     possessed player's own screen. The clean player's quiet badge is a dark green pill. */
  --poss-plum: #2b1018;
  --poss-deep: #160910;
  --poss-line: #a3263a;
  --poss-rim: #5e0b14;
  --poss-red: #c0242f;
  --clean-pill: #133a2a;

  /* aliases kept so existing references keep working */
  --text: var(--ivory);
  --accent: var(--brass);
  --accent-text: #20170a;
  --panel-border: var(--line);

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Hoefler Text", Georgia, "Times New Roman", serif;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
}

* { box-sizing: border-box; }

html, body {
  height: 100%; margin: 0;
  background: var(--bg); color: var(--text);
  font-family: var(--sans);
  overflow: hidden; overscroll-behavior: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
  touch-action: none;
}

#app { position: fixed; inset: 0; }
#view { position: absolute; inset: 0; z-index: 0; }   /* its own stacking context: everything in it stays under the HUD */
#view canvas { display: block; width: 100%; height: 100%; touch-action: none; }
/* ?stats=1 performance readout (for measuring on the device). */
.perf-stats {   /* top left, below the room name and the guest strip */
  position: fixed; left: calc(14px + var(--safe-left)); top: calc(166px + var(--safe-top)); z-index: 50;
  pointer-events: none; padding: 3px 9px; border-radius: 6px; background: rgba(0, 0, 0, 0.72);
  color: #9fe6a8; font: 12px/1.3 ui-monospace, Menlo, monospace;
}
/* The cost tag over a chosen door ("Explore · 2 AP"), positioned by src/render/pathPreview.js. */
.path-label {
  position: absolute; transform: translate(-50%, -100%); pointer-events: none;
  padding: 6px 12px; border-radius: 9px; white-space: nowrap;
  background: rgba(14, 16, 22, 0.9); border: 1.5px solid var(--brass);
  color: var(--ivory); font: 600 15px/1.2 var(--sans); letter-spacing: 0.01em;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}
.path-label::after {
  content: ""; position: absolute; left: 50%; bottom: -7px; width: 10px; height: 10px;
  transform: translateX(-50%) rotate(45deg); background: rgba(14, 16, 22, 0.9);
  border-right: 1.5px solid var(--brass); border-bottom: 1.5px solid var(--brass);
}
/* Tags over the view (src/ui/screenTags.js): one layer under the interface, never in the way of a
   tap. Each tag is placed by its top-left corner; the script keeps it inside the screen and hides it
   while it would cover the interface. */
.tag-layer { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.tag-layer > * { position: absolute; left: 0; top: 0; white-space: nowrap; }
/* Over a fogged room the active guest can explore now (src/render/fog.js). */
.fog-label {
  padding: 5px 11px; border-radius: 999px;
  background: rgba(14, 16, 22, 0.82); border: 1.5px solid var(--brass);
  color: var(--ivory); font: 600 14px/1.2 var(--sans); letter-spacing: 0.02em;
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.45), 0 0 14px rgba(255, 204, 102, 0.22);
}
.fog-label.dim { border-color: var(--line); color: var(--ivory-dim); box-shadow: 0 3px 12px rgba(0, 0, 0, 0.45); }
/* Over a revealed room next door the active guest can walk into (src/ui/goTags.js): quieter than Explore. */
.go-label {
  padding: 3px 9px; border-radius: 999px;
  background: rgba(14, 16, 22, 0.6); border: 1px solid rgba(239, 231, 214, 0.28);
  color: rgba(239, 231, 214, 0.86); font: 600 12.5px/1.2 var(--sans); letter-spacing: 0.02em;
}
/* One name tag per room with guests in it, only when the view is zoomed far out (src/ui/guestTags.js). */
.guest-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px 2px 6px; border-radius: 999px;
  background: rgba(14, 16, 22, 0.82); border: 1px solid var(--line);
  color: var(--ivory); font: 600 12.5px/1.25 var(--sans);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}
.guest-tag .gt-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.guest-tag .gt-sep { color: var(--ivory-dim); padding: 0 1px; }
.guest-tag .gt-more { color: var(--ivory-dim); padding-left: 3px; }
.guest-tag.active { border: 1.5px solid var(--brass-bright); background: rgba(40, 32, 14, 0.9); }

/* A reusable brass-framed surface: a hairline brass border with a dark inner reveal. */
.framed {
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.55), inset 0 0 0 2px var(--line-soft), 0 8px 22px rgba(0, 0, 0, 0.4);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.label-caps { font-size: 11px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass); }

/* HUD */
#hud { position: absolute; inset: 0; pointer-events: none; }
#hud > * { pointer-events: none; }
#hud button, #hud [role="button"] { pointer-events: auto; }

.hud-top-left {
  position: absolute; top: calc(var(--safe-top) + 12px); left: calc(var(--safe-left) + 14px);
  display: flex; flex-direction: column; gap: 7px; align-items: flex-start;
}
.hud-top-right {
  position: absolute; top: calc(var(--safe-top) + 12px); right: calc(var(--safe-right) + 14px);
  display: flex; flex-direction: column; gap: 7px; align-items: flex-end;
}
/* Components below set display:flex/grid, which overrides the browser's default
   [hidden] rule. This makes `el.hidden = true` reliable everywhere. */
[hidden] { display: none !important; }
.hud-top-center {
  position: absolute; top: calc(var(--safe-top) + 8px); left: 50%; transform: translateX(-50%);
  max-width: min(760px, 66vw);
}

/* Room name + round: framed serif plates */
.place {
  font-family: var(--serif); font-size: 19px; font-weight: 600; color: var(--ivory);
  padding: 7px 16px; border-radius: 11px; letter-spacing: 0.01em;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.round-label {
  font-family: var(--serif); font-size: 16px; color: var(--ivory-dim);
  padding: 6px 15px; border-radius: 11px; background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.safe-badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 999px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: #bfe8c8; background: rgba(70, 150, 100, 0.16); border: 1px solid rgba(120, 200, 150, 0.4);
}
.safe-badge[hidden] { display: none; }
.safe-badge .shield { font-size: 12px; }

/* Objective progress: public information, so it sits in the header beside the round counter.
   Pips fill with brass as objectives are recovered and turn green when the exit opens. */
.objectives {
  display: inline-flex; align-items: center; gap: 9px; padding: 6px 14px; border-radius: 11px;
  background: var(--panel); border: 1px solid var(--line); color: var(--ivory-dim);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.objectives .obj-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brass);
}
.obj-pips { display: inline-flex; gap: 5px; }
.obj-pip {
  width: 11px; height: 11px; border-radius: 50%; border: 1px solid var(--line);
  background: rgba(0,0,0,0.35); transition: background 0.25s ease, box-shadow 0.25s ease;
}
.obj-pip.on { background: var(--brass); border-color: var(--brass-bright); box-shadow: 0 0 7px rgba(201,162,78,0.55); }
.objectives .obj-count { font-family: var(--serif); font-size: 15px; font-variant-numeric: tabular-nums; }
.objectives.complete { border-color: rgba(120,200,150,0.55); color: #bfe8c8; }
.objectives.complete .obj-label { color: #9fe3b8; }
.objectives.complete .obj-pip.on { background: #6fc492; border-color: #9fe3b8; box-shadow: 0 0 7px rgba(120,200,150,0.6); }

/* Restart practice: deliberately quieter than the turn actions, and it asks before wiping the game.
   44 px tall: the smallest comfortable touch target. */
.ctl.restart {
  height: 44px; min-width: 0; padding: 0 13px; font-family: var(--serif); font-size: 13px;
  font-weight: 600; letter-spacing: 0.02em; color: var(--muted); border-radius: 10px;
}
.ctl.restart:active { color: var(--ivory-dim); }
.ctl.restart[hidden] { display: none; }

/* Possessed: a barely-there dark plum shadow in the far corners of the hotel view (the possessed
   player's own screen only). It sits UNDER the interface (z-index 0, before #hud in the page), so it
   never tints or dims a panel or a button, and it is dark, not a red glow (a red edge reads as "hurt"). */
.possess-tint {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(130% 95% at 50% 45%, rgba(22,9,16,0) 62%, rgba(43,10,20,0.2) 88%, rgba(30,6,14,0.32) 100%);
}
.possess-tint[hidden] { display: none; }

.portrait-svg { display: block; width: 100%; height: 100%; }
.portrait-img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; }
/* No picture (yet, or it failed to load): a plain navy plate with a brass silhouette, no face, no glasses
   (src/ui/portrait.js); the alt text stays for screen readers but is never drawn over the tile. */
.portrait-img.portrait-missing {
  color: transparent; font-size: 0;
  background: #161b2b url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 118'%3E%3Cg fill='%23b48a46' fill-opacity='.38'%3E%3Ccircle cx='50' cy='43' r='17'/%3E%3Cpath d='M14 118c2-27 17-41 36-41s34 14 36 41z'/%3E%3C/g%3E%3C/svg%3E") center / cover no-repeat;
}
/* A possessed portrait is its own image (the same face with red eyes, assets/portraits/*-possessed.jpg).
   If a guest ever has only a normal image, the private view shows it unchanged — no colour wash on
   the face; the crimson plate around it says the rest. The public strip always asks for normal. */
.portrait-img.possessed { filter: none; }

/* ---- Top player strip: portrait cards with turn / next indicators, on a charcoal plate so the
   names stay readable over bright walls ---- */
.players-strip {
  display: flex; gap: 8px; justify-content: center; padding: 5px 12px 7px; border-radius: 16px;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 8px 22px rgba(0,0,0,0.4);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.mini-player { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 74px; }
.mini-flag { height: 14px; font-size: 11px; line-height: 14px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: transparent; white-space: nowrap; }
.mini-player.active .mini-flag { color: var(--brass-bright); }
.mini-player.next .mini-flag { color: var(--ivory-dim); }
.mini-portrait {
  width: 60px; height: 60px; border-radius: 12px; overflow: hidden; position: relative;
  border: 1px solid var(--line-soft); background: var(--panel-solid);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5);
}
.mini-player.active .mini-portrait {
  border-color: var(--brass); box-shadow: 0 0 0 2px rgba(0,0,0,0.4), 0 0 16px rgba(201,162,78,0.55);
}
.mini-player.next .mini-portrait { border-color: var(--player-color, var(--line)); }
.mini-portrait::after {
  content: ''; position: absolute; left: 8px; right: 8px; bottom: 0; height: 3px; border-radius: 2px;
  background: var(--player-color);
}
.mini-name {
  font-family: var(--serif); font-size: 13px; font-weight: 600; color: var(--ivory-dim);
  max-width: 74px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mini-player.active .mini-name { color: var(--ivory); }
.mini-player.dead { opacity: 0.4; }
.mini-player.dead .mini-name { text-decoration: line-through; }
/* legacy hook (kept; tag text set by JS, styled minimally) */
.turn-tag { display: none; }

/* ---- Bottom bar: one container shares the width between the player panel (left), the hand
   opener (centre) and the controls (right). Flex items shrink instead of overlapping. ---- */
.hud-bottom {
  position: absolute; left: calc(var(--safe-left) + 12px); right: calc(var(--safe-right) + 12px);
  bottom: calc(var(--safe-bottom) + 12px);
  display: flex; align-items: flex-end; gap: 12px; flex-wrap: nowrap;
}
.hud-bottom-left { flex: 0 1 auto; min-width: 0; max-width: 360px; }
.hud-bottom-right { flex: 0 0 auto; margin-left: auto; }
.player-panel {
  display: flex; align-items: stretch; gap: 14px; padding: 12px 16px 12px 12px; border-radius: 16px;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 8px 22px rgba(0,0,0,0.42);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
/* Possessed (the player's own screen only): the reference's private plate — dark plum-crimson, a
   brighter brass border and a thin crimson line just inside it (::before). */
.player-panel { position: relative; }
.player-panel.possessed {
  border-color: rgba(201,162,78,0.8);
  background:
    radial-gradient(90% 120% at 0% 0%, rgba(110,20,38,0.42), rgba(110,20,38,0) 70%),
    linear-gradient(160deg, rgba(43,16,24,0.95), rgba(22,9,16,0.96));
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.45), 0 8px 22px rgba(0,0,0,0.45), 0 0 18px rgba(163,38,58,0.22);
}
.player-panel.possessed::before {
  content: ''; position: absolute; inset: 3px; border-radius: 13px; pointer-events: none;
  border: 1px solid rgba(163,38,58,0.85);
}
.player-panel.possessed .portrait-slot { border-color: var(--brass); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 0 10px rgba(163,38,58,0.35); }
.portrait-slot {
  width: 74px; height: 88px; border-radius: 12px; overflow: hidden; flex: none; align-self: center;
  border: 1px solid var(--brass); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5);
}
.player-meta { display: flex; flex-direction: column; gap: 7px; min-width: 132px; justify-content: center; }
.player-name { font-family: var(--serif); font-size: 20px; font-weight: 700; color: var(--ivory); letter-spacing: 0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat { display: flex; align-items: center; gap: 8px; }
.stat-label { min-width: 58px; font-size: 12px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }

.health { display: flex; gap: 5px; }
.health .bar { width: 26px; height: 10px; border-radius: 2px; background: rgba(255,255,255,0.08); border: 1px solid var(--line-soft); }
.health .bar.full { background: var(--crimson); border-color: #e88178; box-shadow: 0 0 6px rgba(207,74,64,0.5); }

.ap-pips { display: flex; gap: 5px; }
.ap-pips .pip { width: 12px; height: 12px; border-radius: 50%; background: rgba(255,255,255,0.08); border: 1px solid var(--line-soft); }
.ap-pips .pip.full { background: var(--brass); border-color: var(--brass-bright); box-shadow: 0 0 6px rgba(201,162,78,0.5); }
.ap-count { font-size: 13px; font-weight: 700; color: var(--ivory-dim); margin-left: 2px; white-space: nowrap; }
.ap-count.empty { color: #ffb3a7; }
/* Extra action points from an Espresso: warm copper pips after the normal row, set a little apart. */
.ap-pips .pip.bonus { border-color: rgba(232,150,90,0.55); }
.ap-pips .pip.bonus.full { background: #e0894a; border-color: #ffc89a; box-shadow: 0 0 7px rgba(224,137,74,0.7); }
.ap-pips .pip:not(.bonus) + .pip.bonus { margin-left: 4px; }
.ap-pips.many { gap: 3px; }
.ap-pips.many .pip { width: 10px; height: 10px; }
.ap-count.bonus { color: #ffc89a; }
.ap-line { font-size: 13px; color: var(--muted); }  /* legacy */

.private-link {
  align-self: flex-start; margin: -10px 0 -10px -6px; padding: 0 6px; min-height: 48px; display: inline-flex; align-items: center;
  background: none; border: none; touch-action: manipulation;
  color: var(--brass); font-size: 13px; font-weight: 600; letter-spacing: 0.04em; cursor: pointer; font-family: var(--sans);
}
.private-link:active { color: var(--brass-bright); }

/* ---- Bottom-centre: the hand, held as a fan of face-up cards (src/ui/handFan.js) ----
   The fan takes the width left between the player panel and the buttons, so it can never cover
   either. The strip itself lets taps through to the floor; only the cards catch them. Each card's
   place on the arc is three custom properties set by the script: --x, --y and --r. */
.hand-fan {
  position: relative; z-index: 0;   /* its own stacking context: cards never rise above an overlay */
  flex: 1 1 0; min-width: 0; align-self: flex-end;
  height: var(--fan-h, 150px); pointer-events: none;
}
.fan-card {
  position: absolute; left: 0; bottom: calc(var(--fan-drop, 0px) - var(--fan-sink, 0px)); width: var(--fan-w, 96px); aspect-ratio: 2 / 3;
  padding: 0; border: none; border-radius: 7% / 4.7%; overflow: hidden; cursor: pointer;
  background: #1a1a1c; touch-action: manipulation; pointer-events: auto;
  transform-origin: 50% 100%;
  transform: translate(var(--x, 0px), var(--y, 0px)) rotate(var(--r, 0deg));
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(201, 162, 78, 0.35);
  transition: transform 0.16s ease-out, box-shadow 0.16s ease-out;
}
.hand-fan.settling .fan-card { transition: none; }
/* Over the hand limit during a turn (allowed; settled when the turn ends): a calm brass label just
   above the fan, centred. Never catches taps. */
.fan-limit {
  position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%); z-index: 70;
  width: max-content; max-width: min(92vw, 480px); padding: 4px 12px; border-radius: 999px; pointer-events: none;
  white-space: nowrap;   /* one line on every iPad: the words are kept short (handLimitWarning in src/ui/cards.js) */
  font: 700 12.5px/1.35 var(--sans); letter-spacing: 0.02em; color: var(--ivory); text-align: center;
  background: rgba(14, 16, 22, 0.86); border: 1px solid var(--brass); box-shadow: 0 4px 12px rgba(0,0,0,0.45);
}
.fan-limit[hidden] { display: none; }
.fan-card img { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; -webkit-user-drag: none; }
.fan-card .fan-name { display: flex; align-items: center; justify-content: center; height: 100%; padding: 6px; font-family: var(--serif); font-weight: 700; color: var(--ivory); }
/* The Revolver's shots, top LEFT: the next card in the fan covers each card's right-hand side. When
   the fan is crowded (.tight) only the number shows. */
.fan-card .fan-badge {
  position: absolute; top: 5%; left: 5%; padding: 1px 6px; border-radius: 999px; font-size: 12px; font-weight: 800;
  white-space: nowrap; color: #2a2016; background: var(--brass-bright); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
.fan-card .fan-badge b { font-weight: 800; }
.hand-fan.tight .fan-badge .unit { display: none; }
.hand-fan.tight .fan-badge { min-width: 19px; text-align: center; padding: 1px 5px; }
.fan-card.evil { box-shadow: 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(154, 107, 208, 0.7); }
/* Lift: the pointer over a card (mouse) or a finger on it (touch) raises it clear of the screen edge. */
.fan-card.lift { z-index: 60 !important; transform: translate(var(--x, 0px), calc(var(--y, 0px) - var(--fan-lift, 26px))) rotate(0deg) scale(1.1); box-shadow: 0 12px 26px rgba(0, 0, 0, 0.6), 0 0 0 2px var(--brass-bright), 0 0 22px rgba(201, 162, 78, 0.45); }
@media (hover: hover) {
  .fan-card:hover { z-index: 60 !important; transform: translate(var(--x, 0px), calc(var(--y, 0px) - var(--fan-lift, 26px))) rotate(0deg) scale(1.1); box-shadow: 0 12px 26px rgba(0, 0, 0, 0.6), 0 0 0 2px var(--brass-bright), 0 0 22px rgba(201, 162, 78, 0.45); }
}
.fan-card:focus-visible { outline: 2px solid var(--brass-bright); outline-offset: 2px; }
/* A card that has just come into the hand (a search, a trade) is dealt in from just above. It starts
   close to its place, so a finger already on that place is on the card. */
.fan-card.dealt { animation: fan-deal 0.4s cubic-bezier(0.2, 0.8, 0.25, 1) both; }
@keyframes fan-deal {
  from { opacity: 0; transform: translate(var(--x, 0px), calc(var(--y, 0px) - 44px)) rotate(0deg) scale(1.18); }
  to { opacity: 1; transform: translate(var(--x, 0px), var(--y, 0px)) rotate(var(--r, 0deg)); }
}

/* ---- The search icon: a brass magnifier floating over the room's search spot (src/ui/searchSpot.js).
   Its position is one transform written by the script; the pulse lives on the inner badge. ---- */
.search-spot {
  position: absolute; left: 0; top: 0; z-index: 4;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  margin: -30px 0 0 -40px; width: 80px; padding: 0; border: none; background: none;
  cursor: pointer; touch-action: manipulation; pointer-events: auto; will-change: transform;
}
.search-spot .ss-badge {
  position: relative; width: 60px; height: 60px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; color: #3a2a10;
  background: radial-gradient(circle at 38% 30%, #fbf5e6 0%, var(--ivory) 45%, #d9cba9 100%);
  border: 3px solid var(--brass);
  box-shadow: 0 0 0 2px rgba(20, 16, 8, 0.55), 0 6px 16px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(255, 255, 255, 0.6);
}
.search-spot .ss-glass { width: 36px; height: 36px; }
.search-spot.live .ss-badge { animation: ss-pulse 1.8s ease-in-out infinite; }
@keyframes ss-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 2px rgba(20, 16, 8, 0.55), 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 0 rgba(232, 202, 128, 0.55); }
  50% { transform: scale(1.08); box-shadow: 0 0 0 2px rgba(20, 16, 8, 0.55), 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 10px rgba(232, 202, 128, 0); }
}
.search-spot .ss-caption {
  padding: 2px 9px; border-radius: 999px; white-space: nowrap;
  font: 700 12.5px/1.35 var(--sans); letter-spacing: 0.03em; color: var(--ivory);
  background: rgba(14, 16, 22, 0.88); border: 1px solid var(--line);
}
.search-spot .ss-hint {
  display: none; position: absolute; right: -8px; bottom: -6px; width: 26px; height: 26px; border-radius: 50%;
  align-items: center; justify-content: center; color: var(--brass-bright);
  background: #1b1c24; border: 1.5px solid var(--brass);
}
.search-spot .ss-hint svg { width: 17px; height: 17px; }
.search-spot.dark .ss-hint { display: flex; }
/* Dimmed: cannot be searched right now (too dark, no actions, nothing left) — a tap says why. */
.search-spot.dark .ss-badge, .search-spot.ap .ss-badge, .search-spot.empty .ss-badge {
  filter: grayscale(0.75) brightness(0.62); border-color: var(--brass-dim);
}
.search-spot.dark .ss-caption, .search-spot.ap .ss-caption, .search-spot.empty .ss-caption { color: var(--ivory-dim); border-color: var(--line-soft); }
.search-spot:active .ss-badge { transform: scale(0.94); }

/* The fan and the search icon step aside the moment a private, public or end screen is up (the script
   hides them too). */
#app:has(#handoff-overlay:not([hidden]), #encounter-overlay:not([hidden]), #end-overlay:not([hidden]),
  #notice-overlay:not([hidden]), #map-overlay:not([hidden]), #discard-overlay:not([hidden]),
  #start-overlay:not([hidden]), #ask-overlay:not([hidden])) :is(#hand-fan, .search-spot) { display: none !important; }

/* ---- Bottom-right: camera controls (separate) + action buttons ---- */
.hud-bottom-right { display: flex; flex-direction: column; align-items: flex-end; gap: 12px; }
.control-row { display: flex; gap: 10px; align-items: center; }
.action-row { display: flex; gap: 12px; align-items: stretch; }

/* Camera / map controls: quiet, circular, clearly separate from turn actions. */
.ctl {
  appearance: none; height: 50px; min-width: 50px; padding: 0 14px; border-radius: 12px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: rgba(16,18,26,0.8); border: 1px solid var(--line-soft); color: var(--ivory-dim);
  font: inherit; font-size: 22px; cursor: pointer; touch-action: manipulation;
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.ctl:active { transform: scale(0.96); }
.ctl.round { width: 50px; border-radius: 50%; }
.ctl.centre svg { display: block; width: 24px; height: 24px; }
.ctl.map { font-size: 15px; font-weight: 600; font-family: var(--serif); letter-spacing: 0.02em; }
.ctl.map .ico { font-size: 18px; }

/* Turn-action buttons: a clear two-line format (label + cost / reason). */
.btn {
  appearance: none; border: 1px solid var(--line); background: var(--panel); color: var(--text);
  font: inherit; border-radius: 13px; padding: 10px 18px; min-height: 52px; min-width: 52px;
  cursor: pointer; touch-action: manipulation;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  transition: transform 0.08s ease, background 0.15s ease, opacity 0.15s ease;
}
.btn:active { transform: scale(0.97); }
.btn.action, .btn.end { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 1px; }
/* The Search sub-label names the search point, which can be long: keep it on one line. */
.btn.action .btn-sub, .btn.end .btn-sub { max-width: 22ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.btn .btn-main { font-family: var(--serif); font-size: 17px; font-weight: 700; letter-spacing: 0.01em; line-height: 1.1; }
.btn .btn-sub { font-size: 12.5px; font-weight: 600; color: var(--ivory-dim); letter-spacing: 0.01em; line-height: 1.2; }
.btn.primary { background: linear-gradient(180deg, #e6c877, #c9a24e); color: var(--accent-text); border-color: var(--brass-bright); }
.btn.primary .btn-main { color: #20170a; }
.btn.primary .btn-sub { color: #4a3712; }
.btn.primary:active { filter: brightness(0.96); }
.btn.end { min-width: 150px; }
.btn.action { min-width: 108px; }
.btn:disabled { opacity: 0.62; cursor: default; }
.btn:disabled .btn-main { color: var(--ivory-dim); }
.btn:disabled .btn-sub { color: #eaa898; font-weight: 700; }
/* legacy button shapes still used by overlays/modals */
.btn.round { width: 52px; height: 52px; border-radius: 50%; padding: 0; font-size: 22px; line-height: 1; }
.btn.wide { min-width: 132px; }
.btn.big { font-size: 20px; padding: 16px 34px; min-height: 56px; font-family: var(--serif); font-weight: 700; }
.ap-cost {
  display: inline-block; min-width: 16px; margin-left: 4px; padding: 0 6px; border-radius: 7px;
  background: rgba(201,162,78,0.22); color: var(--brass); font-size: 12px; font-weight: 800;
}

/* Move-confirm bar */
.confirm-bar {
  position: absolute; left: 50%; bottom: calc(var(--safe-bottom) + 244px); transform: translateX(-50%);
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap; justify-content: center;
  padding: 12px 14px 12px 20px; max-width: 92vw; border-radius: 14px;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 8px 22px rgba(0,0,0,0.45);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); animation: rise 0.15s ease-out;
}
.confirm-bar[hidden] { display: none; }
#confirm-text { font-family: var(--serif); font-size: 16px; color: var(--ivory); }
.confirm-actions { display: flex; gap: 12px; flex: none; }   /* Move and Cancel never part */

/* Toast */
.toast {
  position: absolute; left: 50%; bottom: calc(var(--safe-bottom) + 196px); transform: translateX(-50%);
  padding: 11px 18px; border-radius: 12px; font-size: 15px; white-space: nowrap; max-width: 90vw;
  text-overflow: ellipsis; overflow: hidden; color: var(--ivory);
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 8px 20px rgba(0,0,0,0.5);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); animation: rise 0.18s ease-out;
}
.toast[hidden] { display: none; }
@keyframes rise { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* ---- Overlays / panels / modals ---- */
.overlay { position: absolute; inset: 0; background: var(--scrim); z-index: 10; }
.overlay.center { display: flex; align-items: center; justify-content: center; padding: 24px; }
.overlay[hidden] { display: none; }

.card {
  text-align: center; border-radius: 20px; padding: 30px 38px; max-width: 92vw;
  background: var(--panel-solid); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), inset 0 0 0 2px var(--line-soft), 0 18px 50px rgba(0,0,0,0.6);
}
.card h1 { margin: 0 0 6px; font-family: var(--serif); font-size: clamp(28px, 5vw, 44px); font-weight: 700; letter-spacing: 0.01em; color: var(--ivory); }
.card p { margin: 0 0 22px; text-wrap: balance; }
/* Start and end screens: the script writes one line per fact; keep those breaks. */
#start-sub, #end-summary { white-space: pre-line; line-height: 1.5; }
.muted { color: var(--muted); }

/* Full-height panel (kept for general use); its header styles are shared by the card view. */
.panel {
  position: absolute; inset: calc(var(--safe-top) + 16px) calc(var(--safe-right) + 16px) calc(var(--safe-bottom) + 16px) calc(var(--safe-left) + 16px);
  border-radius: 18px; display: flex; flex-direction: column; overflow: hidden;
  background: var(--panel-solid); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5);
}
.panel-header {
  display: flex; align-items: center; gap: 10px; padding: 12px 12px 12px 20px;
  border-bottom: 1px solid var(--line-soft);
}
.panel-header .panel-title { font-family: var(--serif); font-size: 19px; font-weight: 700; color: var(--ivory); }
.panel-header .lock { font-size: 12px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); display: inline-flex; align-items: center; gap: 5px; }
.panel-header .spacer { flex: 1; }
.panel-note { padding: 10px 20px 14px; color: var(--muted); font-size: 13px; }

.banner {
  margin: 12px 16px 0; padding: 11px 14px; border-radius: 12px; font-weight: 600; font-size: 14px;
  background: rgba(255,255,255,0.05); border: 1px solid var(--line); color: var(--ivory);
}
.banner[hidden] { display: none; }
.banner.info { background: rgba(143,216,255,0.14); border-color: rgba(143,216,255,0.45); color: #bfe6ff; }

/* A row of card tiles (the prompts, the hand-over screens). */
.cards { display: flex; gap: 12px; align-content: flex-start; }

/* ---- The card view: one card of the hand shown large, beside what it does (src/ui/hand.js) ---- */
.cv-panel {
  display: flex; flex-direction: column; width: min(760px, 94vw); max-height: 94vh; overflow: hidden;
  border-radius: 18px; background: var(--panel-solid); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), inset 0 0 0 2px var(--line-soft), 0 18px 50px rgba(0,0,0,0.6);
  animation: cv-in 0.18s ease-out;
}
@keyframes cv-in { from { transform: translateY(18px) scale(0.97); opacity: 0.4; } to { transform: none; opacity: 1; } }
.cv-body { display: flex; gap: 22px; padding: 16px 20px 6px; min-height: 0; overflow: hidden; flex: 1; }
.cv-left { flex: none; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.cv-card .big-card { width: clamp(180px, min(28vw, 38vh), 280px); }
.cv-nav { display: flex; align-items: center; gap: 14px; }
.cv-nav .btn.round { width: 48px; height: 48px; font-size: 26px; }
.cv-pos { min-width: 5ch; text-align: center; font-family: var(--serif); font-size: 14px; color: var(--ivory-dim); }
.card-view .hand-detail { flex: 1; width: auto; min-width: 0; padding-top: 4px; }

/* A card shown large (the card view, the found-card reveal): the face, then its name and words. */
.big-card { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.big-card .bc-face {
  position: relative; width: 100%; aspect-ratio: 2 / 3; border-radius: 7% / 4.7%; overflow: hidden;
  box-shadow: 0 10px 28px rgba(0,0,0,0.6), 0 0 0 1px rgba(201,162,78,0.45);
}
.big-card.evil .bc-face { box-shadow: 0 10px 28px rgba(0,0,0,0.6), 0 0 0 1px rgba(154,107,208,0.7); }
.big-card .bc-face img { display: block; width: 100%; height: 100%; object-fit: cover; }
.big-card .bc-face .art { height: 100%; border-radius: 0; }
.big-card .face-badge { position: absolute; top: 7%; right: 8%; padding: 2px 9px; border-radius: 999px; font-size: 13px; font-weight: 800;
  color: #2a2016; background: var(--brass-bright); box-shadow: 0 1px 4px rgba(0,0,0,0.5); }
.big-card .bc-name { font-family: var(--serif); font-size: 20px; font-weight: 700; color: var(--brass-bright); }
.big-card.evil .bc-name { color: var(--evil); }
.big-card .bc-desc { font-size: 14px; line-height: 1.45; color: var(--ivory); max-width: 30ch; text-align: center; }

/* The found-card reveal on the hand-over card: one or two cards, large. */
.handoff-found { display: flex; gap: 26px; justify-content: center; margin: 6px auto 10px; }
.handoff-found .big-card { width: clamp(170px, min(24vw, 40vh), 250px); animation: found-in 0.45s cubic-bezier(0.2, 0.8, 0.25, 1) both; }
.handoff-found .big-card:nth-child(2) { animation-delay: 0.12s; }
.handoff-found.pair .big-card { width: clamp(150px, min(21vw, 34vh), 220px); }
@keyframes found-in { from { opacity: 0; transform: translateY(26px) rotate(-3deg) scale(0.9); } to { opacity: 1; transform: none; } }
.card.handoff-card.found h1 { color: var(--brass-bright); }
/* Practice: nobody to hide from, so the room stays in view behind the reveal. */
.overlay.handoff.soft { background: rgba(8, 9, 14, 0.74); }

.hand-detail {
  width: 264px; flex: none; border-left: 1px solid var(--line-soft); padding-left: 18px;
  display: flex; flex-direction: column; gap: 10px; overflow-y: auto;
}
.hand-detail .d-name { font-family: var(--serif); font-size: 22px; font-weight: 700; color: var(--brass-bright); }
.hand-detail .d-line { font-size: 14.5px; line-height: 1.5; color: var(--ivory); }
.hand-detail .d-line b { color: var(--brass-bright); font-weight: 700; }
.hand-detail .d-desc { font-size: 14.5px; line-height: 1.5; color: var(--ivory); }
.hand-detail .d-tag { font-size: 13px; line-height: 1.4; color: var(--ivory-dim); }
.hand-detail .d-tag.d-warn { color: var(--brass-bright); }   /* a card that can be played, but would be wasted */
.hand-detail .d-empty { color: var(--muted); font-size: 15px; margin: auto 0; }
.hand-detail .btn { align-self: flex-start; }
/* Hand Mirror: one short name button per guest in the room, wrapping two or three to a row. */
.hand-detail .d-targets { display: flex; flex-wrap: wrap; gap: 8px; }
.hand-detail .d-targets .btn { align-self: auto; min-height: 44px; padding: 8px 14px; }
.lantern-track { display: flex; align-items: center; gap: 8px; margin-top: 2px; }
.lantern-track .pip { width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--line); display: flex; align-items: center; justify-content: center; font-size: 14px; color: var(--brass-dim); }
.lantern-track .pip.on { color: var(--brass-bright); border-color: var(--brass); background: rgba(201,162,78,0.16); }
.lantern-track .lt-count { font-size: 13px; color: var(--ivory-dim); margin-left: 4px; }

/* Card tile: warm ivory card face, restrained brass border, a generous illustration area and a
   clear name — matching the approved card concept. */
.card-tile {
  width: 162px; flex: none; border-radius: 14px; padding: 10px 10px 12px; display: flex; flex-direction: column; gap: 8px;
  background: linear-gradient(180deg, #f5eeda, #e6dabe);
  border: 1px solid var(--brass); color: #2a2016;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.55), 0 5px 14px rgba(0,0,0,0.4);
}
.card-tile .art {
  height: 132px; border-radius: 9px; display: flex; align-items: center; justify-content: center;
  background: #efe3c8;
  background: radial-gradient(120% 100% at 50% 34%, color-mix(in srgb, var(--card-tint) 52%, #efe3c8), #d8c8a2);
  border: 1px solid rgba(140,114,51,0.55); box-shadow: inset 0 0 0 1px rgba(255,255,255,0.45); overflow: hidden;
}
.card-tile .art .glyph { font-size: 58px; line-height: 1; color: #3a2c14; color: color-mix(in srgb, var(--card-tint) 68%, #3a2c14); text-shadow: 0 1px 1px rgba(255,255,255,0.4); }
.card-tile .art img { width: 100%; height: 100%; object-fit: cover; }
/* Drawn icons (src/ui/cardIcons.js) sit inside the tinted illustration area, ivory-on-tint. */
.card-tile .art svg.icon { width: 72%; height: 72%; color: #3a2c14; color: color-mix(in srgb, var(--card-tint) 55%, #2a2016); filter: drop-shadow(0 1px 0 rgba(255,255,255,0.35)); }
.card-tile.evil .art svg.icon { color: #6a2fa8; }
.card-tile .cname { font-family: var(--serif); font-weight: 700; font-size: 15px; color: #2a2016; text-align: center; }
/* Finished card faces (owner designs, src/ui/cards.js CARD_FACE): the image IS the card — frame, art and
   name — so the tile drops its ivory frame; the name stays for screen readers; text below reads ivory. */
.card-tile.face { background: none; border: none; box-shadow: none; padding: 0; gap: 6px; }
.card-tile.face .face-img { position: relative; aspect-ratio: 2 / 3; border-radius: 7% / 4.7%; overflow: hidden;
  box-shadow: 0 6px 16px rgba(0,0,0,0.5); }
.card-tile.face .face-img img { display: block; width: 100%; height: 100%; object-fit: cover; }
.card-tile.face .face-badge { position: absolute; top: 7%; right: 8%; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 800;
  color: #2a2016; background: var(--brass-bright); box-shadow: 0 1px 4px rgba(0,0,0,0.5); }
.card-tile.face .cname { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.card-tile.face .cdesc { color: var(--ivory-dim); }
.card-tile.face.selected { border: none; box-shadow: none; }
.card-tile.face.selected .face-img { box-shadow: 0 0 0 3px var(--brass-bright), 0 0 22px rgba(201,162,78,0.6); }
.card-tile.face.evil .face-img { box-shadow: 0 6px 16px rgba(0,0,0,0.5), 0 0 0 1px rgba(154,107,208,0.6); }
.card-tile .cdesc { font-size: 12px; color: #5c4a2e; line-height: 1.3; text-align: center; }
.card-tile.count .badge { align-self: center; padding: 1px 9px; border-radius: 999px; font-size: 12px; font-weight: 700; background: rgba(140,114,51,0.2); color: #6a5326; }
.card-tile.selectable { cursor: pointer; }
.card-tile.selectable:active { transform: scale(0.98); }
.card-tile.selected { border-color: var(--brass-bright); box-shadow: 0 0 0 2px var(--brass-bright), 0 0 20px rgba(201,162,78,0.5); }
.card-tile.evil { border-color: #9a6bd0; }
.card-tile.evil .art { border-color: rgba(154,107,208,0.55); }
.card-tile.evil .art .glyph { color: #7a3fb0; }
.card-tile .btn { margin-top: auto; min-height: 40px; padding: 8px 10px; }
.card-tile .btn .btn-main { font-size: 14px; }

/* Modals (encounter, discard) */
.modal {
  border-radius: 18px; padding: 22px 24px; width: min(600px, 94vw); max-height: 90vh; overflow-y: auto; text-align: center;
  background: var(--panel-solid); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), inset 0 0 0 2px var(--line-soft), 0 18px 50px rgba(0,0,0,0.6);
}
.modal-title { font-family: var(--serif); font-size: 22px; font-weight: 700; margin-bottom: 6px; color: var(--ivory); }
.modal-sub { color: var(--muted); font-size: 14px; margin-bottom: 14px; }
.modal-body { margin: 8px 0 16px; }
.modal-body .cards { flex-wrap: wrap; justify-content: center; padding: 4px 0; }
.modal-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.modal-actions .btn { min-height: 50px; }
.modal-actions .btn .btn-main, .modal .btn { font-family: var(--serif); font-weight: 700; }
#discard-cards { flex-wrap: wrap; justify-content: center; }
.who { display: inline-flex; align-items: center; gap: 7px; font-weight: 700; font-family: var(--serif); }
.who .dot { width: 12px; height: 12px; border-radius: 50%; background: var(--player-color); box-shadow: 0 0 0 1px rgba(0,0,0,0.4); }
.result-line { font-size: 15px; line-height: 1.5; margin: 6px 0; }
.result-line.good { color: #9ce0b0; }
.result-line.bad { color: #ff9a8f; }
.result-line.evil { color: #dcc4ff; }

/* Buttons inside modals default to serif label if they contain no .btn-main */
.modal .btn:not(.action):not(.end) { font-family: var(--serif); font-weight: 700; font-size: 16px; }

/* ---- Map: framed floor-plan ---- */
.map-panel {
  position: absolute; inset: calc(var(--safe-top) + 16px) calc(var(--safe-right) + 16px) calc(var(--safe-bottom) + 16px) calc(var(--safe-left) + 16px);
  border-radius: 18px; display: flex; flex-direction: column; overflow: hidden;
  background: var(--panel-solid); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), inset 0 0 0 2px var(--line-soft);
}
.map-header {
  display: flex; align-items: center; justify-content: space-between; padding: 12px 12px 12px 20px;
  border-bottom: 1px solid var(--line-soft);
}
.map-header .panel-title { font-family: var(--serif); font-size: 19px; font-weight: 700; color: var(--ivory); }
#map-canvas { flex: 1; width: 100%; height: 100%; display: block; }
.map-legend {
  display: flex; gap: 16px; flex-wrap: wrap; padding: 10px 20px; border-top: 1px solid var(--line-soft);
  font-size: 12px; color: var(--muted);
}
.map-legend span { display: inline-flex; align-items: center; gap: 6px; }
.map-legend .sw { width: 14px; height: 14px; border-radius: 3px; border: 1px solid var(--line); }
.map-legend .sw.here { background: rgba(201,162,78,0.3); border-color: var(--brass); }
.map-legend .sw.searched { background: rgba(120,200,150,0.18); border-color: rgba(120,200,150,0.5); }
.map-legend .sw.frontier { background: var(--brass-bright); border-color: var(--brass); height: 4px; margin-top: 5px; }
/* A guest on the plan: a round dot in their colour (src/map.js; the guest whose turn it is: an arrow).
   The swatch is quartered in four of the guests' colours, so it reads as "a coloured dot", not one guest. */
.map-legend .sw.guest {
  width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid #1d1509;
  background: conic-gradient(#e6bc5c 0 25%, #73d4e6 0 50%, #2f8cff 0 75%, #e673ac 0);
}
/* Rooms with jobs carry a small mark on the plan (drawn in src/map.js in the same colours). */
.map-legend .mk-bar { width: 18px; height: 18px; flex: none; }
.map-legend .mk { font-family: var(--serif); font-weight: 700; font-size: 14px; line-height: 1; }
.map-legend .mk.infirmary { color: #f08c84; }
.map-legend .mk.switchboard { color: #9fd0f0; }
.map-legend .mk.linen { color: #efe7d6; }
.map-legend .mk.drop { color: var(--brass-bright); }   /* the brass ◆ src/map.js draws in a room's corner */

/* The one-off announcement when the exit opens, and the end-screen button pair. */
.card.notice { max-width: 440px; }
.notice-rule {
  width: 54px; height: 2px; margin: 0 auto 18px; border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--brass-bright), transparent);
}
.end-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* The "hands are full" prompt reuses the modal/card styles; it only needs its found card
   centred and a little breathing room above the choice buttons. */

/* Smaller landscape iPads (≈1024–1080 wide): tighten the bottom row so the player panel, the hand
   button and the action buttons never overlap. Camera settings and gestures are untouched. */
@media (max-width: 1120px) {
  .hud-bottom-left { max-width: 40vw; }
  .player-panel { gap: 10px; padding: 10px 12px 10px 10px; }
  .player-meta { min-width: 96px; }
  .portrait-slot { width: 60px; height: 74px; }
  .action-row { gap: 8px; }
  .control-row { gap: 8px; }
  .btn.action { min-width: 92px; padding: 9px 12px; }
  .btn.end { min-width: 128px; padding: 9px 14px; }
  .btn .btn-main { font-size: 16px; }
  .ctl { height: 48px; min-width: 48px; padding: 0 10px; }   /* never below 48 px */
  .ctl.map { font-size: 14px; }
}
/* Portrait orientation / narrow: the bottom bar becomes two rows — hand opener + camera controls
   above, player panel + turn actions below — so nothing is squeezed or overlapped. */
@media (max-width: 900px) {
  .hud-bottom { display: grid; grid-template-columns: auto 1fr auto; grid-template-areas: "hand hand ctl" "panel panel actions"; align-items: end; column-gap: 10px; row-gap: 10px; }
  .hud-bottom-left { grid-area: panel; max-width: none; }
  .hand-fan { grid-area: hand; width: 100%; }
  .hud-bottom-right { display: contents; }     /* its two rows become grid items */
  .control-row { grid-area: ctl; justify-self: end; }
  .action-row { grid-area: actions; justify-self: end; }
  .hand-detail { width: 200px; padding-left: 14px; }
  .card-tile { width: 144px; }
  .card-tile .art { height: 116px; }
  .card-tile .art .glyph { font-size: 50px; }
  .mini-player { width: 64px; }
  .mini-portrait { width: 54px; height: 54px; }
  .hud-top-center { max-width: 94vw; }
  .players-strip { gap: 6px; padding: 4px 8px 6px; }
}
@media (max-width: 620px) {
  .hand-detail { width: 168px; }
  .mini-player { width: 58px; }
  .mini-portrait { width: 48px; height: 48px; }
  .player-meta { min-width: 88px; }
}

/* ============================================================================================
   PHASE 1 — hot-seat: the pass-the-device flow, the turn timer and the public escape readout.
   ============================================================================================ */

/* Escape progress sits beside the objectives in the header. Public information. */
.objectives.escapes { border-color: rgba(140,200,170,0.35); }

/* The turn clock. Shown only while the active player's action phase is running. */
.turn-timer {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 10px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--line-soft);
}
.turn-timer[hidden] { display: none; }
.tt-track { width: 104px; height: 6px; border-radius: 999px; background: rgba(0,0,0,0.45); overflow: hidden; }
.tt-fill { height: 100%; width: 100%; background: linear-gradient(90deg, var(--brass), var(--brass-bright)); transform-origin: left center; }   /* (shrunk by hud.showTimer: transform: scaleX) */
.tt-seconds { font-family: var(--serif); font-size: 14px; font-variant-numeric: tabular-nums; color: var(--ivory-dim); min-width: 3.2ch; text-align: right; }
.turn-timer.low { border-color: rgba(207,74,64,0.6); }
.turn-timer.low .tt-fill { background: linear-gradient(90deg, #8c3a34, var(--crimson)); }
.turn-timer.low .tt-seconds { color: #f0b4ae; }

/* Public per-guest lines in the top strip: where they are (a short room name), then health. Never a
   role, and never a card count (card counts are private). Readable at arm's length; a long name ends in
   an ellipsis. The health line is only the hearts, so it sits close under the room. */
.mini-where { display: flex; flex-direction: column; align-items: center; gap: 1px; font-size: 12px; line-height: 1.25; color: var(--ivory-dim); text-align: center; width: calc(100% + 8px); max-width: 82px; }
.mini-where .mini-room, .mini-where .mini-stats { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mini-where .mini-stats { font-size: 12px; line-height: 1; letter-spacing: 0.5px; color: #e88178; }
.mini-where .mini-stats:empty { display: none; }
.mini-player.escaped { opacity: 0.55; }
.mini-player.escaped .mini-name { color: #9fe3b8; }

/* The Offer button in the action row. */
.btn.action.locked { opacity: 0.75; }
.btn.action.evil .btn-sub { color: var(--evil); }

/* --- The hand-over overlay ------------------------------------------------------------------
   Deliberately plain and opaque: it has to hide the 3D view completely so the previous player's
   position and the room they were in are not still readable behind it. */
.overlay.handoff { background: rgba(8, 9, 14, 0.97); }
.handoff-card {
  max-width: min(760px, 94vw); max-height: 92vh; overflow-y: auto;
  text-align: center; padding: 26px 30px;
}
.handoff-card h1 { font-size: clamp(22px, 4vw, 34px); margin-bottom: 4px; }
.handoff-card p { margin-bottom: 14px; }
.handoff-kicker {
  font-family: var(--serif); font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--brass); margin-bottom: 8px;
}
.handoff-card .modal-actions {
  margin-top: 18px; position: sticky; bottom: -26px; padding: 12px 0 2px;
  background: linear-gradient(to bottom, rgba(20,24,36,0), var(--panel-solid) 35%);
}
/* The pass screen carries nothing private, so it stays large and calm. */
.handoff-card.pass h1 { color: var(--brass-bright); }

.role-badge {
  display: flex; flex-direction: column; gap: 4px; align-items: center;
  margin: 4px auto 12px; padding: 10px 16px; border-radius: 14px; max-width: 620px;
  border: 1px solid var(--line); background: rgba(0,0,0,0.3);
}
.role-badge[hidden] { display: none; }
.role-badge .role-word { font-family: var(--serif); font-weight: 700; letter-spacing: 0.18em; font-size: clamp(20px, 3.4vw, 30px); }
.role-badge .role-line { font-size: 13px; line-height: 1.45; color: var(--ivory-dim); }
.role-badge.good { border-color: var(--line); }
/* The role word as the badge pill (the same pills as the player panel's; .tell-pill below). */
.role-badge .role-word.tell-pill { font: 800 clamp(14px, 1.9vw, 17px)/1.45 var(--sans); padding: 5px 18px 5px 20px; letter-spacing: 0.2em; }
.role-badge.evil {
  position: relative; border-color: rgba(201,162,78,0.8);
  background:
    radial-gradient(70% 140% at 0% 0%, rgba(110,20,38,0.45), rgba(110,20,38,0) 70%),
    linear-gradient(160deg, var(--poss-plum), var(--poss-deep));
  box-shadow: 0 0 22px rgba(163,38,58,0.22);
}
.role-badge.evil::before {
  content: ''; position: absolute; inset: 3px; border-radius: 11px; pointer-events: none;
  border: 1px solid rgba(163,38,58,0.85);
}

.handoff-notes { display: flex; flex-direction: column; gap: 8px; margin: 0 auto 14px; max-width: 620px; }
.handoff-notes[hidden] { display: none; }
.handoff-note {
  padding: 10px 14px; border-radius: 10px; font-size: 14px; line-height: 1.45; text-align: left;
  background: rgba(180,107,255,0.12); border: 1px solid rgba(180,107,255,0.4); color: #e6d6ff;
}

.handoff-hand { justify-content: center; margin-bottom: 14px; }
.handoff-hand[hidden] { display: none; }
/* Your own hand on the role / turn screens: the tiles share one row, as wide as fits (--n tiles, set
   in src/ui/handoff.js; 118px at most, 72px at least, then the row wraps), so a full hand (the rules
   allow more than 6 during a turn, plus a stack of Possession cards) stays above the Start button. */
.handoff-hand { --n: 5; gap: 10px; }
.handoff-hand .card-tile { width: clamp(72px, calc((100% - (var(--n) - 1) * 10px) / var(--n) - 0.5px), 118px); }
.handoff-hand .card-tile .art { min-height: 70px; }
/* A whole hand can hold 7 or more cards (a possessed guest's Possession cards, a Hand Mirror look at
   someone else's), so the row wraps instead of running off both sides. */
.handoff-hand { flex-wrap: wrap; }
.handoff-card.mirror .handoff-hand .card-tile { width: 108px; }

/* --- The Offer chooser ----------------------------------------------------------------------- */
.offer-block {
  margin: 4px auto 0; padding: 14px; border-radius: 14px; max-width: 700px;
  border: 1px solid var(--line); background: rgba(0,0,0,0.25);
}
.offer-block[hidden] { display: none; }
.offer-label {
  font-family: var(--serif); font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--brass); margin-bottom: 10px;
}
/* The row wraps: a big hand (6 cards + 3 Possession cards) ran off both sides, and a centred row that
   spills off the left can never be scrolled back. Tiles shrink a little on short screens. */
.offer-block .cards { justify-content: center; flex-wrap: wrap; }
.offer-block .card-tile { width: clamp(84px, 13vh, 100px); }   /* six to a row in the 700 px block */
.offer-block .card-tile .art { min-height: 62px; }
.card-tile.nothing { background: linear-gradient(180deg, #2a2e3a, #1e222c); border-color: var(--line-soft); color: var(--ivory-dim); }
.card-tile.nothing .cname { color: var(--ivory-dim); }
.card-tile.nothing .art { background: rgba(0,0,0,0.3); border-color: var(--line-soft); }
.card-tile.nothing .art .glyph { color: var(--muted); text-shadow: none; }
.offer-intent { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }
.offer-intent[hidden] { display: none; }
.btn.intent { min-height: 48px; }
.btn.intent.on { border-color: var(--brass-bright); box-shadow: 0 0 0 2px var(--brass-bright); }
.btn.intent.evil.on { border-color: var(--evil); box-shadow: 0 0 0 2px var(--evil); color: #e6d6ff; }
.offer-summary { margin-top: 12px; font-size: 14px; color: var(--ivory-dim); font-family: var(--serif); }
.offer-summary.locked { color: var(--brass); }

/* The end-of-turn discard prompt: the whole hand must fit on an iPad at once. Six cards in a
   single row overflowed the box and clipped the outer cards out of reach, so the rows wrap and
   the tiles are compact; the found card shrinks once the player is choosing what to drop. */
#discard-overlay .modal { max-height: 94vh; overflow-y: auto; }
#discard-cards { flex-wrap: wrap; justify-content: center; padding: 4px 0; }
#discard-cards .card-tile { width: 112px; }
#discard-cards .card-tile .art { min-height: 70px; }
#discard-cards .card-tile .cdesc { display: none; }
/* Hot-seat: whose private moment this is (the turn has not passed yet). */
.discard-kicker { margin-bottom: 4px; font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--brass); }
.discard-kicker[hidden] { display: none; }

/* The last round before dawn: the header round label says so and turns a warning colour. */
.round-label.final { color: #f0b4ae; border-color: rgba(207, 74, 64, 0.65); background: rgba(80, 24, 22, 0.55); }

/* --- Turn sideways: portrait or a window under ~900 px wide ----------------------------------
   The game is laid out for landscape only; rather than squeeze it, a calm card asks for the iPad to
   be turned. Pure CSS (no script), above every other screen; main.js pauses the turn clock meanwhile. */
.rotate-overlay { display: none; }
@media (orientation: portrait), (max-width: 900px) {
  .rotate-overlay {
    display: flex; position: fixed; inset: 0; z-index: 200; align-items: center; justify-content: center;
    padding: calc(var(--safe-top) + 24px) calc(var(--safe-right) + 24px) calc(var(--safe-bottom) + 24px) calc(var(--safe-left) + 24px);
    background: radial-gradient(120% 90% at 50% 35%, #1a1e2c, var(--bg) 70%);
  }
}
.rotate-card { max-width: min(460px, 100%); padding: 30px 32px 26px; }
.rotate-card h1 { font-size: clamp(24px, 6vw, 32px); text-wrap: balance; }
.rotate-card p { margin: 10px 0 0; line-height: 1.45; text-wrap: balance; }
.rotate-icon { width: 132px; height: 99px; margin: 0 auto 14px; display: block; }
.rotate-icon rect { fill: none; stroke-width: 3; }
.rotate-icon .ri-portrait { stroke: var(--brass-dim); stroke-dasharray: 5 5; }
.rotate-icon .ri-landscape { stroke: var(--brass-bright); fill: rgba(201,162,78,0.12); }
.rotate-icon path { fill: none; stroke: var(--brass); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }

/* ---- The possessed guest's own tell (src/ui/souls.js): the POSSESSED badge, how many Possession
   cards ("souls") they can still trade and their possessed portrait (red eyes), on the crimson plate.
   Only on that guest's private surfaces — the role screen, the card view and their own panel. ---- */
/* The badge: a dark pill with a brass edge and a crimson hairline inside it, ivory capitals, and a
   small "Only you can see this" under it. The clean player's is the same pill in dark green, quiet,
   with no caption (src/hud.js shows it in a match only, never in practice). */
.tell-badge { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; flex: none; }
.tell-badge[hidden] { display: none; }
.tell-pill {
  display: inline-block; padding: 2px 10px 2px 11px; border-radius: 999px; white-space: nowrap;
  font: 800 12px/1.4 var(--sans); letter-spacing: 0.13em; text-transform: uppercase; color: var(--ivory);
  background: linear-gradient(180deg, #2a0d15, #13070b); border: 1px solid var(--brass);
  box-shadow: inset 0 0 0 1px rgba(163,38,58,0.95), 0 1px 4px rgba(0,0,0,0.5);
}
.tell-badge.clean .tell-pill, .role-badge.good .tell-pill {
  background: linear-gradient(180deg, #17442f, var(--clean-pill)); border-color: rgba(201,162,78,0.85);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.35), 0 1px 4px rgba(0,0,0,0.45);
}
.tell-note { font-family: var(--serif); font-size: 12px; line-height: 1.2; color: var(--ivory-dim); white-space: nowrap; letter-spacing: 0.01em; }

.souls-chip {
  display: inline-flex; align-items: center; gap: 8px; align-self: center;
  padding: 4px 12px 4px 5px; border-radius: 999px; font-size: 14px; font-weight: 600; line-height: 1.3;
  background: rgba(10,4,7,0.55); border: 1px solid rgba(163,38,58,0.9); color: var(--ivory);
}
.souls-chip b { font-size: 17px; font-weight: 800; color: #fff; }
.souls-chip .souls-card { width: 20px; aspect-ratio: 2 / 3; border-radius: 2px; object-fit: cover; flex: none;
  box-shadow: 0 0 0 1px rgba(201,162,78,0.7); }
/* None left: said calmly — no warning look, the card greyed. */
.souls-chip.none { background: rgba(255,255,255,0.04); border-color: rgba(163,38,58,0.45); color: var(--ivory-dim); font-weight: 500; border-radius: 12px; }
.souls-chip.none .souls-card { filter: grayscale(1) brightness(0.6); box-shadow: 0 0 0 1px rgba(201,162,78,0.35); }
.souls-chip.compact { padding: 2px 9px 2px 4px; font-size: 12px; gap: 6px; }
.souls-chip.compact b { font-size: 14px; }
.souls-chip.compact .souls-card { width: 14px; }

/* Hand-over screens (role reveal, private turn): the brass card keeps its look, with a faint crimson
   warmth at the top; the role box inside is the crimson plate (portrait, POSSESSED badge, souls). */
.handoff-card.possessed {
  border-color: rgba(201,162,78,0.7);
  background: radial-gradient(120% 90% at 50% 0%, rgba(110,20,38,0.24), rgba(110,20,38,0) 60%), var(--panel-solid);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), inset 0 0 0 2px var(--line-soft), 0 0 32px rgba(163,38,58,0.14), 0 18px 50px rgba(0,0,0,0.6);
}
.role-badge.with-portrait { flex-direction: row; align-items: center; gap: 16px; text-align: left; padding: 12px 18px 12px 12px; }
.role-badge .role-portrait { width: 62px; height: 74px; flex: none; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--brass); box-shadow: 0 0 12px rgba(163,38,58,0.4); }
.role-badge .role-text { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; min-width: 0; }
.role-badge .role-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
.role-badge .role-head .tell-badge { align-items: center; }
.role-badge .role-head .tell-note { font-size: 12.5px; }
.role-badge .role-head .souls-chip { align-self: center; }
.role-badge.with-portrait .role-text { gap: 6px; }
.role-badge.evil .role-line { color: var(--ivory-dim); }
/* A private note on the possessed guest's own role screen ("You were possessed by …"): the plate's
   palette, not the general violet note. */
.handoff-card.possessed .handoff-note { background: rgba(94,11,20,0.22); border-color: rgba(163,38,58,0.6); color: var(--ivory); }

/* The card view: the banner is the crimson plate (portrait, badge, words, count); the backdrop behind
   the panel is only a little darker and warmer. */
.card-view.possessed { background: radial-gradient(120% 90% at 50% 40%, rgba(30,10,16,0.55), rgba(14,5,9,0.78)); }
.card-view.possessed .cv-panel { box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), inset 0 0 0 2px var(--line-soft), 0 0 30px rgba(163,38,58,0.2), 0 18px 50px rgba(0,0,0,0.6); }
.banner.possessed {
  position: relative; display: flex; align-items: center; gap: 14px; padding: 8px 14px 8px 8px; font-weight: 500; color: var(--ivory);
  border-color: rgba(201,162,78,0.8);
  background:
    radial-gradient(60% 160% at 0% 0%, rgba(110,20,38,0.45), rgba(110,20,38,0) 70%),
    linear-gradient(160deg, var(--poss-plum), var(--poss-deep));
}
.banner.possessed::before {
  content: ''; position: absolute; inset: 3px; border-radius: 9px; pointer-events: none;
  border: 1px solid rgba(163,38,58,0.85);
}
.banner.possessed[hidden] { display: none; }
.banner.possessed b { font-weight: 800; letter-spacing: 0.06em; color: #fff; }
.banner .banner-portrait { width: 50px; height: 60px; flex: none; border-radius: 8px; overflow: hidden;
  border: 1px solid var(--brass); box-shadow: 0 0 10px rgba(163,38,58,0.35); }
/* The words, with the souls chip beside them, in room for two lines on every card: on the Possession
   card (one short line, no chip) the banner stays the same height, so the card and the ‹ › arrows below
   it do not jump as you step through the hand. */
.banner .banner-text { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1; min-height: 40px; }
.banner .banner-words { flex: 1; min-width: 140px; line-height: 1.4; }
.banner .banner-text .souls-chip { flex: none; align-self: center; }
/* None left (every Possession card traded away): the chip carries a whole sentence, so it takes a share
   of the row and wraps inside its own box instead of squeezing the words to nothing. */
.banner .banner-text .souls-chip.none { flex: 0 1 240px; min-width: 0; font-size: 13px; line-height: 1.3; padding: 5px 12px 5px 6px; }
/* The ×N badge sits in the dark corner beside the mirror, clear of the card's printed title. */
.big-card .face-badge.souls { top: auto; bottom: 21%; right: 6%; padding: 3px 12px; font-size: 22px; color: #fff;
  background: #7a2bd0; border: 1px solid #d7b3ff; box-shadow: 0 0 12px rgba(180,107,255,0.75), 0 2px 6px rgba(0,0,0,0.6); }
.card-tile.face .face-badge.souls { top: 6%; right: 7%; padding: 2px 9px; font-size: 16px; color: #fff;
  background: #7a2bd0; border: 1px solid #d7b3ff; box-shadow: 0 0 8px rgba(180,107,255,0.7); }
.card-view .d-line.souls-line { color: var(--ivory); }
.card-view .d-line.souls-line b { color: #fff; }

/* The player panel: the name, with the player's own badge beside it (POSSESSED + its caption, or a
   quiet CLEAN in a match), and the souls count. The pill lines up with the name; the caption hangs
   under the pill. */
.player-name-row { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
.player-name-row .player-name { line-height: 22px; min-width: 0; }
.player-name-row .tell-badge { margin-top: 1px; }
.panel-role[hidden], .panel-souls[hidden] { display: none; }
.panel-souls { display: flex; margin: -2px 0 -4px; }
.fan-card .fan-badge.souls { color: #fff; background: #7a2bd0; border: 1px solid #d7b3ff; box-shadow: 0 0 8px rgba(180,107,255,0.7); }


/* ==========================================================================================
   Main menu (src/ui/menu.js) over the lobby (src/menu/lobbyScene.js), the lift fade, and the
   match's own pieces: the feed, the Menu button, the end-of-match roles.
   ========================================================================================== */
/* The lobby behind the menu, soft and a little dim; the blur eases away as the lift sequence starts. */
#view canvas { transition: filter 1.4s ease, transform 1.4s ease; }
#view.blurred canvas { filter: blur(2.5px) saturate(0.92) brightness(0.82); transform: scale(1.03); }

.menu { position: fixed; inset: 0; z-index: 40; }
.menu-shade {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(90deg, rgba(7, 8, 13, 0.9) 0%, rgba(7, 8, 13, 0.72) 30%, rgba(7, 8, 13, 0.18) 58%, rgba(7, 8, 13, 0) 75%),
    radial-gradient(140% 120% at 70% 45%, rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, 0.55) 100%);
  transition: opacity 0.9s ease;
}
.menu-panel {
  position: absolute; top: 50%; left: calc(var(--safe-left) + max(28px, 6vw));
  transform: translateY(-50%); width: min(430px, 44vw);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.menu.leaving .menu-panel { opacity: 0; transform: translate(-24px, -50%); pointer-events: none; }
.menu.leaving .menu-shade { opacity: 0; }
.menu-screen { animation: menuIn 0.45s ease both; }
@keyframes menuIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.menu-kicker {
  font-size: 12px; font-weight: 700; letter-spacing: 0.22em; text-transform: uppercase; color: var(--brass);
  margin-bottom: 8px;
}
.menu-title {
  margin: 0; font-family: var(--serif); font-weight: 700; font-size: clamp(46px, 6.4vw, 64px); line-height: 0.98;
  letter-spacing: 0.01em; color: var(--brass-bright);
  background: linear-gradient(180deg, #f6e2a8 0%, #e2bd67 55%, #a8812f 100%); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; text-shadow: none; filter: drop-shadow(0 3px 14px rgba(0, 0, 0, 0.55));
}
.menu-tag { margin: 12px 0 26px; font-family: var(--serif); font-style: italic; font-size: 18px; color: var(--ivory-dim); }
.menu-h2 { margin: 0 0 18px; font-family: var(--serif); font-size: 32px; font-weight: 700; color: var(--ivory); }
.menu-buttons { display: flex; flex-direction: column; gap: 12px; }
.menu-btn {
  appearance: none; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 3px;
  min-height: 64px; padding: 12px 22px; border-radius: 14px; cursor: pointer; text-align: left;
  background: rgba(16, 18, 26, 0.86); border: 1px solid var(--line); color: var(--ivory);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5), 0 10px 28px rgba(0, 0, 0, 0.35);
  transition: transform 0.12s ease, border-color 0.2s ease, background 0.2s ease;
  font: inherit;
}
.menu-btn:active { transform: scale(0.98); }
.menu-btn:disabled { opacity: 0.5; cursor: default; }
.menu-btn .mb-main { font-family: var(--serif); font-size: 22px; font-weight: 700; letter-spacing: 0.01em; }
.menu-btn .mb-sub { font-size: 13px; color: var(--ivory-dim); }
.menu-btn.primary { background: linear-gradient(180deg, #e9cb7c, #c69c47); border-color: var(--brass-bright); color: #1f1608; }
.menu-btn.primary .mb-sub { color: #4a3712; }
.menu-btn.small { min-height: 54px; padding: 10px 22px; align-items: center; font-family: var(--serif); font-size: 18px; font-weight: 700; }
.menu-loading { margin-top: 16px; font-size: 13px; color: var(--muted); letter-spacing: 0.04em; }
.menu-actions { display: flex; gap: 12px; margin-top: 22px; }
.menu-actions .menu-btn { flex: 1; }
.menu-field { margin-bottom: 18px; }
.mf-label { font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ivory-dim); margin-bottom: 8px; }
.mf-note { margin-top: 8px; font-size: 14px; line-height: 1.45; color: var(--muted); min-height: 1.45em; text-wrap: pretty; }
.seg { display: flex; gap: 6px; flex-wrap: wrap; }
.seg-btn {
  appearance: none; flex: 1 1 0; min-width: 0; min-height: 48px; padding: 8px 12px; border-radius: 11px; cursor: pointer;
  background: rgba(16, 18, 26, 0.78); border: 1px solid var(--line-soft); color: var(--ivory-dim);
  font-family: var(--serif); font-size: 16px; font-weight: 700; white-space: nowrap;
}
.seg-btn.on { background: rgba(201, 162, 78, 0.2); border-color: var(--brass); color: var(--brass-bright); box-shadow: inset 0 0 0 1px rgba(232, 202, 128, 0.25); }

/* The table filling up (matchmaking). */
.mm-seats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.mm-seat {
  display: grid; grid-template-columns: 14px 1fr auto; align-items: center; gap: 12px;
  min-height: 46px; padding: 8px 14px; border-radius: 11px;
  background: rgba(16, 18, 26, 0.72); border: 1px solid var(--line-soft);
}
.mm-seat .mm-dot { width: 12px; height: 12px; border-radius: 50%; background: rgba(255, 255, 255, 0.12); }
.mm-seat .mm-name { font-family: var(--serif); font-size: 18px; font-weight: 700; color: var(--ivory); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mm-seat .mm-guest { font-size: 13px; color: var(--muted); }
.mm-seat.empty .mm-name { color: var(--muted); font-weight: 600; font-style: italic; animation: mmWait 1.6s ease-in-out infinite; }
.mm-seat.joined { animation: mmJoin 0.4s ease both; }
.mm-seat.joined .mm-dot { background: var(--player-color, var(--brass)); box-shadow: 0 0 10px var(--player-color, var(--brass)); }
.mm-seat.you { border-color: var(--brass); }
.mm-seat.you .mm-name { color: var(--brass-bright); }
@keyframes mmWait { 50% { opacity: 0.45; } }
@keyframes mmJoin { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: none; } }

/* Black between the lobby and the game. */
.fade { position: fixed; inset: 0; z-index: 90; background: #000; opacity: 0; pointer-events: none; transition: opacity var(--fade-ms, 600ms) ease; }
.fade.on { opacity: 1; pointer-events: auto; }

/* Top right: Restart practice and the Menu button side by side. */
.top-buttons { display: flex; gap: 8px; align-items: center; }
.ctl.leave {
  height: 44px; min-width: 0; padding: 0 13px; font-family: var(--serif); font-size: 13px;
  font-weight: 600; letter-spacing: 0.02em; color: var(--muted); border-radius: 10px;
}

/* The feed: what the other guests just did. */
/* (narrow enough to stay clear of the guest strip in the middle — six guests at 1024 wide included) */
.feed {
  position: absolute; left: calc(var(--safe-left) + 14px); top: calc(var(--safe-top) + 92px);
  display: flex; flex-direction: column; gap: 4px; max-width: min(340px, 33vw, calc(50vw - 272px)); min-width: 0; pointer-events: none;
}
.feed-line {
  font-size: 13px; line-height: 1.3; padding: 5px 10px; border-radius: 8px; color: var(--ivory-dim);
  background: rgba(14, 16, 22, 0.8); border: 1px solid var(--line-soft);
  animation: feedIn 0.35s ease both; transition: opacity 0.5s ease;
}
.feed-line.me { color: var(--ivory); border-color: var(--line); }
.feed-line.gone { opacity: 0; }
@keyframes feedIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* The strip: the player's own guest, and "Playing" on a computer guest's turn. */
.mini-player.me .mini-name { color: var(--brass-bright); }
.mini-player.me .mini-flag { color: var(--brass); }
.mini-player.active.me .mini-flag { color: var(--brass-bright); }
/* On another guest's turn the End turn button says whose turn it is and waits. */
.btn.primary.end.waiting { background: var(--panel); border-color: var(--line); opacity: 1; }
.btn.end.waiting:disabled .btn-main { color: var(--ivory-dim); }
.btn.end.waiting:disabled .btn-sub { color: var(--muted); font-weight: 600; }

/* A guest making up their mind (meeting.waiting). */
.result-line.waiting { display: flex; align-items: center; gap: 10px; justify-content: center; }
.think-dots { display: inline-flex; gap: 4px; }
.think-dots i { width: 7px; height: 7px; border-radius: 50%; background: var(--brass); animation: think 1.1s ease-in-out infinite; }
.think-dots i:nth-child(2) { animation-delay: 0.15s; }
.think-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes think { 0%, 80%, 100% { opacity: 0.25; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-3px); } }

/* The end of a match: everyone's role, now that it is over. */
.end-reveal { display: grid; gap: 6px; margin: 2px auto 22px; width: min(540px, 80vw); text-align: left; }
.er-row {
  /* (a fixed role column, wide enough for POSSESSED, so every row's columns line up; "You" takes only
  its own width and the name the rest, cut short with "…" rather than run under "You") */
  display: grid; grid-template-columns: 12px minmax(0, 1fr) auto 92px 64px; gap: 10px; align-items: center;
  padding: 7px 12px; border-radius: 10px; background: rgba(255, 255, 255, 0.03); border: 1px solid var(--line-soft);
}
.er-row.you { border-color: var(--brass); }
.er-dot { width: 11px; height: 11px; border-radius: 50%; background: var(--player-color, var(--brass)); }
.er-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--serif); font-size: 17px; font-weight: 700; color: var(--ivory); }
.er-who { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.er-row.you .er-who { color: var(--brass-bright); font-weight: 700; }
.er-role { font-size: 12px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; }
.er-role.evil { color: #e46b74; }   /* the possessed guests, revealed at the end: the crimson of the possessed look */
.er-role.good { color: #9fe3b8; }
.er-status { font-size: 12px; color: var(--muted); text-align: right; }
.er-row.dead .er-name { text-decoration: line-through; opacity: 0.7; }
.er-row.escaped .er-status { color: #9fe3b8; font-weight: 700; }
#end-overlay.won #end-title { color: var(--brass-bright); }
#end-overlay.lost #end-title { color: #eaa898; }
@media (max-height: 700px) {
  .menu-tag { margin-bottom: 18px; }
  .menu-btn { min-height: 56px; padding: 9px 18px; }
  .end-reveal { gap: 4px; margin-bottom: 14px; }
  .er-row { padding: 5px 10px; }
}


/* ==== Trade reveal, attack result, feed icons (src/ui/tradeReveal.js, meeting.js, feed.js) ========
   A trade the player is in is SHOWN, not told: the two guests and the two cards, with an effect for
   what happened, on the private hand-over card. Motion is transforms, opacity and small filters on a
   handful of elements; embers, ash and smoke are one canvas (no big blurs). Skipped by a tap. ==== */
.handoff-card.trade-reveal { width: min(940px, 94vw); max-width: min(940px, 94vw); padding: 18px 26px 20px; }
.handoff-card.trade-reveal > h1, .handoff-card.trade-reveal > #handoff-sub { display: none; }
.handoff-card.trade-reveal .handoff-kicker { margin-bottom: 0; }
.handoff-card.trade-reveal .modal-actions { margin-top: 4px; transition: opacity 0.35s ease; }
.handoff-card.trade-reveal.tr-playing .modal-actions { visibility: hidden; opacity: 0; }
.handoff-card:not(.trade-reveal) :is(.tr-stage, .tr-caption) { display: none; }

.tr-stage {
  --H: clamp(230px, 46vh, 420px); --cw: calc(var(--H) * 0.4); --pw: calc(var(--H) * 0.36); --cy: calc(50% - 10px);
  position: relative; height: var(--H); margin: 2px 0 2px; cursor: pointer;
}
.tr-fx { position: absolute; left: -14px; top: -14px; width: calc(100% + 28px); height: calc(100% + 28px); pointer-events: none; z-index: 5; }

/* The two guests: you on the left, them on the right. */
.tr-seat {
  position: absolute; top: var(--cy); width: calc(var(--pw) + 8px); margin-left: calc(var(--pw) / -2 - 4px); margin-top: calc(var(--pw) * -0.667);
  display: flex; flex-direction: column; align-items: center; gap: 8px; animation: tr-seat-in 0.45s ease-out both;
}
.tr-seat.me { left: 10%; }
.tr-seat.them { left: 90%; animation-delay: 0.06s; }
.tr-port {
  position: relative; width: var(--pw); aspect-ratio: 3 / 4; border-radius: 12px; overflow: hidden; background: #12141d;
  border: 1px solid var(--brass); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 8px 22px rgba(0,0,0,0.55);
  transition: box-shadow 0.7s ease, border-color 0.7s ease;
}
.tr-port > img, .tr-port > svg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.tr-port .tr-p2 { opacity: 0; transition: opacity 0.9s ease; }
.tr-seat.turned .tr-p2 { opacity: 1; }
/* Turned (you are possessed) / known (you know they are): the crimson hairline of the possessed plate. */
.tr-seat.turned .tr-port, .tr-seat.known .tr-port {
  border-color: rgba(201,162,78,0.9);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 0 0 2px var(--poss-line), 0 0 22px rgba(163,38,58,0.55), 0 8px 22px rgba(0,0,0,0.55);
}
.tr-port::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(75% 65% at 50% 45%, rgba(150,16,36,0) 35%, rgba(120,10,28,0.72) 100%);
}
.tr-seat.pulse .tr-port::after { animation: tr-flash 1.1s ease-out both; }
.tr-ring {
  position: absolute; left: 0; top: -4px; width: 100%; height: calc(var(--pw) * 4 / 3 + 8px); border-radius: 15px; pointer-events: none; opacity: 0;
  border: 2px solid rgba(208,48,62,0.95); box-shadow: 0 0 16px rgba(192,36,47,0.65), inset 0 0 14px rgba(192,36,47,0.45);
}
.tr-seat.pulse .tr-ring { animation: tr-ring 1s ease-out both; }
.tr-seat.pulse .tr-ring.two { animation-delay: 0.28s; }
.tr-name { display: inline-flex; align-items: center; gap: 7px; font-family: var(--serif); font-weight: 700; font-size: 16px; color: var(--ivory); white-space: nowrap; }
.tr-name .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--player-color); box-shadow: 0 0 0 1px rgba(0,0,0,0.4); }

/* A card: rail (crosses the stage) > card (its slot) > tilt (leans, sinks) > flip (turns) > faces. */
.tr-rail { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
.tr-stage.o-blockedMe .tr-rail.mine, .tr-stage.o-possessedThem .tr-rail.mine { z-index: 2; }
.tr-card {
  position: absolute; top: var(--cy); width: var(--cw); height: calc(var(--cw) * 1.5); margin-left: calc(var(--cw) / -2); margin-top: calc(var(--cw) * -0.75);
  animation: tr-card-in 0.45s cubic-bezier(0.2, 0.8, 0.25, 1) 0.08s both;
}
.tr-card.at-l { left: 31%; }
.tr-card.at-r { left: 69%; }
.tr-rail.theirs .tr-card { animation-delay: 0.16s; }
.tr-tilt { position: absolute; inset: 0; z-index: 0; perspective: 900px; }
.tr-flip { position: absolute; inset: 0; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; }
.tr-flip.down { transform: rotateY(180deg); }
.tr-flip.reveal { animation: tr-flip 0.5s cubic-bezier(0.3, 0.7, 0.3, 1) both; }
.tr-face {
  position: absolute; inset: 0; border-radius: 7% / 4.7%; overflow: hidden; background: #15130f;
  -webkit-backface-visibility: hidden; backface-visibility: hidden;
  box-shadow: 0 10px 26px rgba(0,0,0,0.6), 0 0 0 1px rgba(201,162,78,0.45); transition: box-shadow 0.5s ease;
}
.tr-face img { display: block; width: 100%; height: 100%; object-fit: cover; transition: filter 0.6s ease; }
.tr-back { transform: rotateY(180deg); }
.tr-badge { position: absolute; top: 7%; right: 8%; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 800; color: #2a2016; background: var(--brass-bright); box-shadow: 0 1px 4px rgba(0,0,0,0.5); }
.tr-burn { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* The card you got: a soft brass shimmer and edge. The card you gave: a little dimmer (theirs now). */
.tr-front::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0; transform: translateX(-120%);
  background: linear-gradient(105deg, rgba(255,236,190,0) 36%, rgba(255,236,190,0.5) 50%, rgba(255,236,190,0) 64%);
}
.tr-front.shine::after { animation: tr-shine 0.9s ease-out 0.05s both; }
.tr-card.got .tr-front { box-shadow: 0 10px 26px rgba(0,0,0,0.6), 0 0 0 1.5px var(--brass-bright), 0 0 24px rgba(232,202,128,0.45); }
.tr-card.given .tr-front img { filter: brightness(0.8) saturate(0.85); }
.tr-card.evil-land .tr-front { box-shadow: 0 10px 26px rgba(0,0,0,0.6), 0 0 0 1.5px rgba(208,48,62,0.95), 0 0 26px rgba(163,38,58,0.6); }
.tr-tilt.sink .tr-front { box-shadow: 0 0 0 1.5px rgba(208,48,62,0.95), 0 0 26px rgba(163,38,58,0.7); }
/* A Lantern: it flares (a warm halo with a slow deco sunburst), then gutters out, used up. */
.tr-card.lit .tr-front { box-shadow: 0 10px 26px rgba(0,0,0,0.5), 0 0 0 1.5px rgba(255,220,150,0.95), 0 0 34px rgba(255,190,90,0.65); }
.tr-card.lit .tr-front img { filter: brightness(1.18) saturate(1.1); }
.tr-card.spent .tr-front { box-shadow: 0 8px 20px rgba(0,0,0,0.5), 0 0 0 1px rgba(201,162,78,0.22); }
.tr-card.spent .tr-front img { filter: grayscale(0.85) brightness(0.5); transition: filter 1.1s ease; }
.tr-card.spent .tr-tilt { opacity: 0.72; transition: opacity 1.1s ease; }
.tr-halo {
  position: absolute; left: 50%; top: 42%; width: 300%; height: calc(var(--cw) * 3); z-index: -1; pointer-events: none; border-radius: 50%; opacity: 0;
  transform: translate(-50%, -50%) scale(0.5);
  background: radial-gradient(closest-side, rgba(255,230,170,0.78), rgba(255,186,90,0.34) 36%, rgba(230,140,50,0.11) 62%, rgba(200,110,40,0) 100%);
}
.tr-halo::after {
  content: ''; position: absolute; inset: 6%; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg, rgba(255,222,150,0.22) 0deg 5deg, rgba(255,222,150,0) 5deg 18deg);
  -webkit-mask: radial-gradient(closest-side, #000 28%, transparent 100%); mask: radial-gradient(closest-side, #000 28%, transparent 100%);
}
.tr-halo.flare { animation: tr-flare 0.75s cubic-bezier(0.2, 0.8, 0.3, 1) both; }
.tr-halo.flare::after, .tr-halo.gutter::after { animation: tr-rays 7s linear both; }
.tr-halo.gutter { animation: tr-gutter 1s linear both; }
/* A Possession card burning away (the dissolve itself is a canvas); then only a little ash. */
.tr-card.burning .tr-front { box-shadow: none; background: transparent; }
.tr-card.burnt .tr-flip { visibility: hidden; }
.tr-card.fade-burn .tr-front { animation: tr-fade-burn 0.5s ease-in forwards; }
.tr-ash {
  position: absolute; left: 6%; right: 6%; bottom: -3%; height: 18%; pointer-events: none; opacity: 0; transition: opacity 0.8s ease;
  background: radial-gradient(50% 50% at 50% 60%, rgba(140,130,120,0.34), rgba(80,74,68,0.16) 55%, rgba(60,55,50,0) 100%);
}
.tr-card.burnt .tr-ash { opacity: 1; }
/* The Possession cards you now hold fan out. */
.tr-card.tr-extra { animation: none; opacity: 0; transform: none; transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.25, 1), opacity 0.3s ease; }
.tr-card.tr-extra.fanned { opacity: 1; transform: translate(var(--fan-x), -3%) rotate(var(--fan-r)); }
.tr-card.tr-extra .tr-front { box-shadow: 0 10px 26px rgba(0,0,0,0.6), 0 0 0 1.5px rgba(208,48,62,0.85), 0 0 18px rgba(163,38,58,0.45); }
.tr-tilt.fan-main { transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.25, 1); transform: rotate(var(--fan-r)); }
/* No trade: an empty, dimmed slot (an open hand) for whoever had nothing. */
.tr-empty {
  position: absolute; top: var(--cy); width: var(--cw); height: calc(var(--cw) * 1.5); margin-left: calc(var(--cw) / -2); margin-top: calc(var(--cw) * -0.75);
  border-radius: 7% / 4.7%; border: 2px dashed rgba(201,162,78,0.42);
  background: radial-gradient(80% 60% at 50% 45%, rgba(255,255,255,0.04), rgba(0,0,0,0.25));
  display: flex; align-items: center; justify-content: center; animation: tr-card-in 0.45s ease-out 0.08s both;
}
.tr-empty.at-l { left: 31%; }
.tr-empty.at-r { left: 69%; }
.tr-empty svg { width: 46%; height: auto; fill: none; stroke: rgba(201,162,78,0.55); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.tr-empty.shrug svg { animation: tr-shrug 0.8s ease-in-out both; }

/* The moves. */
.tr-rail.go-cross-r { animation: tr-cross-r 0.9s cubic-bezier(0.55, 0, 0.3, 1) both; }
.tr-rail.go-cross-l { animation: tr-cross-l 0.9s cubic-bezier(0.55, 0, 0.3, 1) both; }
.tr-rail.go-strike-l { animation: tr-strike-l 0.75s cubic-bezier(0.3, 0, 0.2, 1) both; }
.tr-rail.go-strike-r { animation: tr-strike-r 0.75s cubic-bezier(0.3, 0, 0.2, 1) both; }
.tr-rail.go-nudge-r { animation: tr-nudge-r 0.6s ease-out 0.2s both; }
.tr-rail.go-nudge-l { animation: tr-nudge-l 0.6s ease-out 0.2s both; }
.tr-rail.go-sink-r { animation: tr-sink-r 1.1s cubic-bezier(0.5, 0, 0.4, 1) both; }
.tr-rail.go-offer-r { animation: tr-offer-r 1.1s ease-in-out both; }
.tr-tilt.tilt-a { animation: tr-tilt-a 0.9s ease-in-out both; }
.tr-tilt.tilt-b { animation: tr-tilt-b 0.9s ease-in-out both; }
.tr-tilt.sink { animation: tr-sink 1.1s ease-in both; }
@keyframes tr-seat-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes tr-card-in { from { opacity: 0; transform: translateY(24px) scale(0.94); } to { opacity: 1; transform: none; } }
@keyframes tr-cross-r { 0% { transform: translate(0, 0); } 50% { transform: translate(19%, -10%); } 100% { transform: translate(38%, 0); } }
@keyframes tr-cross-l { 0% { transform: translate(0, 0); } 50% { transform: translate(-19%, 10%); } 100% { transform: translate(-38%, 0); } }
@keyframes tr-strike-l { 0% { transform: translate(0, 0); } 70% { transform: translate(-14%, -3%); } 100% { transform: translate(-16%, 0); } }
@keyframes tr-strike-r { 0% { transform: translate(0, 0); } 70% { transform: translate(14%, -3%); } 100% { transform: translate(16%, 0); } }
@keyframes tr-nudge-r { to { transform: translateX(2.5%); } }
@keyframes tr-nudge-l { to { transform: translateX(-2.5%); } }
@keyframes tr-sink-r { 0% { transform: translate(0, 0); } 35% { transform: translate(19%, -10%); } 60% { transform: translate(36%, -1%); } 100% { transform: translate(59%, -3%); } }
@keyframes tr-sink { 0% { transform: rotate(0deg) scale(1); opacity: 1; } 35% { transform: rotate(-7deg) scale(1); } 60% { transform: rotate(0deg) scale(0.92); opacity: 1; } 100% { transform: rotate(0deg) scale(0.22); opacity: 0; } }
@keyframes tr-offer-r { 0%, 100% { transform: translateX(0); } 45%, 60% { transform: translateX(9%); } }
@keyframes tr-tilt-a { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-8deg); } }
@keyframes tr-tilt-b { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(8deg); } }
@keyframes tr-flip { 0% { transform: rotateY(180deg); } 50% { transform: rotateY(90deg) scale(1.06); } 100% { transform: rotateY(0deg); } }
@keyframes tr-shine { 0% { opacity: 0; transform: translateX(-120%); } 15%, 85% { opacity: 1; } 100% { opacity: 0; transform: translateX(120%); } }
@keyframes tr-flare { 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.45); } 35% { opacity: 1; transform: translate(-50%, -50%) scale(1.1); } 100% { opacity: 0.9; transform: translate(-50%, -50%) scale(1); } }
@keyframes tr-rays { from { transform: rotate(0deg); } to { transform: rotate(50deg); } }
@keyframes tr-gutter { 0% { opacity: 0.9; transform: translate(-50%, -50%) scale(1); } 16% { opacity: 0.45; } 28% { opacity: 0.78; } 44% { opacity: 0.22; } 56% { opacity: 0.5; } 74% { opacity: 0.1; } 100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); } }
@keyframes tr-fade-burn { 0% { opacity: 1; filter: none; } 40% { opacity: 1; filter: sepia(1) brightness(1.5) saturate(2); } 100% { opacity: 0; filter: sepia(1) brightness(0.4); } }
@keyframes tr-ring { 0% { opacity: 0; transform: scale(0.92); } 18% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(1.32); } }
@keyframes tr-flash { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }
@keyframes tr-shrug { 0%, 100% { transform: translateX(0) rotate(0deg); } 20% { transform: translateX(-5px) rotate(-6deg); } 45% { transform: translateX(5px) rotate(6deg); } 70% { transform: translateX(-3px) rotate(-3deg); } }
/* Skipped (a tap): every move jumps to where it ends. Reduced motion: every move is short. */
.tr-stage.tr-end, .tr-stage.tr-end *, .tr-stage.tr-end *::before, .tr-stage.tr-end *::after { animation-delay: 0s !important; animation-duration: 0s !important; transition: none !important; }
.tr-stage.tr-reduced *, .tr-stage.tr-reduced *::before, .tr-stage.tr-reduced *::after { animation-duration: 0.3s !important; animation-delay: 0s !important; }

/* The few words under it. */
.tr-caption {
  min-height: 2.6em; margin: 0 auto; max-width: 680px; font-family: var(--serif); font-size: clamp(19px, 2.3vw, 24px); line-height: 1.3;
  color: var(--ivory); text-wrap: balance; opacity: 0; transform: translateY(6px); transition: opacity 0.4s ease, transform 0.4s ease;
}
.tr-caption.on { opacity: 1; transform: none; }
.tr-caption .tr-who { color: var(--brass-bright); }
.tr-caption .tr-evil { color: #e46b74; }
/* Behind the two cards: a faint brass sunburst and rule, the hotel's deco, where the cards change hands. */
.tr-deco {
  position: absolute; left: 50%; top: var(--cy); width: calc(var(--H) * 0.95); height: calc(var(--H) * 0.95); transform: translate(-50%, -50%);
  border-radius: 50%; pointer-events: none; opacity: 0.9;
  background: repeating-conic-gradient(from -2deg, rgba(201,162,78,0.10) 0deg 4deg, rgba(201,162,78,0) 4deg 15deg);
  -webkit-mask: radial-gradient(closest-side, #000 18%, rgba(0,0,0,0.5) 55%, transparent 100%); mask: radial-gradient(closest-side, #000 18%, rgba(0,0,0,0.5) 55%, transparent 100%);
}
.tr-deco::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; transform: translate(-50%, -50%) rotate(45deg);
  background: var(--brass); box-shadow: 0 0 0 3px rgba(201,162,78,0.18);
}

/* The attack result (public, the meeting panel): attacker, the weapon card striking, the target with
   the hearts they lost dropping away. Restrained: a bright slash or a muzzle flash, never blood. */
.atk-stage { display: flex; align-items: flex-start; justify-content: center; gap: clamp(16px, 3.4vw, 34px); margin: 2px 0 6px; }
.atk-seat { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.atk-port {
  position: relative; width: clamp(78px, 12vh, 104px); aspect-ratio: 3 / 4; border-radius: 10px; overflow: hidden; background: #12141d;
  border: 1px solid var(--brass); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.5), 0 6px 18px rgba(0,0,0,0.5);
}
.atk-port > img, .atk-port > svg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.atk-name { font-size: 15px; color: var(--ivory); }
.atk-name .who { gap: 6px; }
.atk-weapon { position: relative; z-index: 2; width: clamp(74px, 11vh, 96px); aspect-ratio: 2 / 3; flex: none; }
.atk-weapon img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 7% / 4.7%; box-shadow: 0 8px 20px rgba(0,0,0,0.55), 0 0 0 1px rgba(201,162,78,0.45); }
.atk-knife .atk-weapon { animation: atk-lunge 0.55s cubic-bezier(0.4, 0, 0.2, 1) 0.15s both; }
.atk-revolver .atk-weapon { animation: atk-recoil 0.5s ease-out 0.5s both; }
.atk-flash {
  position: absolute; right: -62%; top: -6%; width: 110%; aspect-ratio: 1; border-radius: 50%; pointer-events: none; opacity: 0; transform: scale(0.3);
  background: radial-gradient(closest-side, rgba(255,252,232,1), rgba(255,214,120,0.95) 22%, rgba(255,150,50,0.42) 50%, rgba(255,120,30,0) 100%);
}
.atk-flash::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: repeating-conic-gradient(from 0deg, rgba(255,236,170,0.75) 0deg 6deg, rgba(255,236,170,0) 6deg 30deg);
  -webkit-mask: radial-gradient(closest-side, #000 25%, transparent 100%); mask: radial-gradient(closest-side, #000 25%, transparent 100%);
}
.atk-revolver .atk-flash { animation: atk-flash 0.45s ease-out 0.5s both; }
.atk-weapon.gone img { animation: atk-grey 0.8s ease 1.1s both; }
.atk-empty {
  position: absolute; left: 50%; bottom: 9%; transform: translateX(-50%); padding: 2px 9px; border-radius: 999px; white-space: nowrap;
  font: 800 12px/1.4 var(--sans); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ivory-dim);
  background: rgba(20,16,12,0.92); border: 1px solid var(--brass-dim); opacity: 0; animation: atk-tag 0.4s ease 1.2s both;
}
.atk-slash {
  position: absolute; left: -12%; right: -12%; top: 47%; height: 4px; pointer-events: none; opacity: 0; transform: rotate(-32deg) scaleX(0);
  background: linear-gradient(90deg, rgba(255,246,225,0), rgba(255,246,225,0.95) 30%, #fff 50%, rgba(255,246,225,0.95) 70%, rgba(255,246,225,0));
  box-shadow: 0 0 10px rgba(255,236,200,0.85);
}
.atk-knife .atk-slash { animation: atk-slash 0.45s ease-out 0.56s both; }
.atk-port::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at 50% 45%, rgba(255,230,190,0.5), rgba(207,74,64,0.28) 42%, rgba(207,74,64,0) 72%);
}
.atk-target .atk-port { animation: atk-shake 0.45s ease-in-out 0.58s both; }
.atk-target .atk-port::after { animation: atk-hit 0.55s ease-out 0.58s both; }
.atk-stage.killed .atk-target .atk-port > :is(img, svg) { animation: atk-grey 0.9s ease 1.1s both; }
.atk-stage.killed .atk-target .atk-name { opacity: 0.7; }
.atk-hearts { position: relative; display: flex; gap: 4px; margin-top: 1px; }
.atk-heart { position: relative; width: 18px; height: 17px; }
.atk-heart svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.atk-heart .h-o { fill: rgba(255,255,255,0.05); stroke: rgba(207,74,64,0.55); stroke-width: 1.6; }
.atk-heart .h-f { fill: var(--crimson); filter: drop-shadow(0 0 3px rgba(207,74,64,0.6)); transform-origin: 50% 60%; }
.atk-heart.empty .h-f { display: none; }
.atk-heart.lost .h-f { animation: atk-drop 0.75s cubic-bezier(0.5, 0, 0.7, 0.4) calc(0.62s + var(--i, 0) * 0.14s) both; }
.atk-minus {
  position: absolute; right: -30px; top: -2px; font: 800 15px/1 var(--sans); color: #ff9a8f; text-shadow: 0 1px 3px rgba(0,0,0,0.6);
  opacity: 0; animation: atk-minus 1s ease-out 0.66s both;
}
.atk-line { margin: 4px 0 0; color: var(--ivory-dim); }
@keyframes atk-lunge { 0% { transform: none; } 55% { transform: translateX(34px) rotate(10deg); } 100% { transform: none; } }
@keyframes atk-recoil { 0% { transform: none; } 15% { transform: translateX(-8px) rotate(-7deg); } 100% { transform: none; } }
@keyframes atk-flash { 0% { opacity: 0; transform: scale(0.3); } 25% { opacity: 1; transform: scale(1.1); } 100% { opacity: 0; transform: scale(1.45); } }
@keyframes atk-slash { 0% { opacity: 1; transform: rotate(-32deg) scaleX(0); } 40% { opacity: 1; transform: rotate(-32deg) scaleX(1); } 100% { opacity: 0; transform: rotate(-32deg) scaleX(1); } }
@keyframes atk-shake { 0%, 100% { transform: none; } 20% { transform: translateX(-6px); } 40% { transform: translateX(5px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(2px); } }
@keyframes atk-hit { 0% { opacity: 0; } 20% { opacity: 1; } 100% { opacity: 0; } }
@keyframes atk-grey { to { filter: grayscale(1) brightness(0.45); } }
@keyframes atk-tag { from { opacity: 0; } to { opacity: 1; } }
@keyframes atk-drop { 0% { transform: none; opacity: 1; } 22% { transform: scale(1.25); opacity: 1; } 100% { transform: translateY(24px) rotate(28deg) scale(0.7); opacity: 0; } }
@keyframes atk-minus { 0% { opacity: 0; transform: translateY(4px); } 25% { opacity: 1; transform: none; } 75% { opacity: 1; } 100% { opacity: 0.9; transform: translateY(-6px); } }
@media (prefers-reduced-motion: reduce) {
  .atk-stage *, .atk-stage *::before, .atk-stage *::after { animation-duration: 0.01s !important; animation-delay: 0s !important; }
}

/* The feed: a small brass icon at the start of each line (src/ui/feed.js). */
.feed-line.has-icon { display: flex; align-items: center; gap: 8px; padding-left: 6px; }
.feed-text { min-width: 0; }
.feed-icon {
  position: relative; flex: none; width: 24px; height: 24px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 35%, #22252f, #12141b); border: 1px solid rgba(201,162,78,0.55); color: var(--brass-bright);
}
.feed-icon svg { width: 16px; height: 16px; display: block; }
.feed-icon svg.icon { width: 19px; height: 19px; }
.feed-icon.attack { border-color: rgba(207,74,64,0.75); color: #f2b0a6; }
.feed-icon.attack.fatal { background: radial-gradient(circle at 50% 35%, #3a1418, #170a0c); }
.feed-icon.escape { border-color: rgba(159,227,184,0.6); color: #bfeccd; }
/* Two card backs crossing: a trade happened, nothing about what changed hands. */
.feed-icon .fi-back {
  position: absolute; left: 50%; top: 50%; width: 10px; height: 15px; margin: -7.5px 0 0 -5px; border-radius: 1.5px; object-fit: cover;
  box-shadow: 0 0 0 0.75px rgba(232,202,128,0.9), 0 1px 2px rgba(0,0,0,0.6);
}
.feed-icon .fi-back.a { transform: translateX(-2.5px) rotate(-17deg); }
.feed-icon .fi-back.b { transform: translateX(2.5px) rotate(17deg); }

/* === Settings: Music and Sound effects rows (src/audio/) ==============================================
   Six rows now: on a short screen (an iPad mini in landscape, Safari's bars showing) the settings
   panel tightens its spacing so Done stays on screen. */
@media (max-height: 760px) {
  #menu-settings .menu-h2 { margin-bottom: 10px; font-size: 28px; }
  #menu-settings .menu-field { margin-bottom: 11px; }
  #menu-settings .mf-label { margin-bottom: 6px; }
  #menu-settings .seg-btn { min-height: 44px; }
  #menu-settings .menu-actions { margin-top: 14px; }
}

/* === Trade reveal: QA fixes (src/ui/tradeReveal.js) ===================================================
   The effects canvas reaches into the card's side padding and fades out at its left and right edges,
   so smoke near a portrait never stops on a hard line. The Continue button becomes visible (and so
   tappable) a moment after the scene ends: a quick second tap meant to hurry the scene can't close it
   unseen (the script also holds its taps off for that moment). No trade: the empty hand a little larger. */
.tr-fx {
  left: -24px; width: calc(100% + 48px);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 40px, #000 calc(100% - 40px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 40px, #000 calc(100% - 40px), transparent);
}
.handoff-card.trade-reveal .modal-actions { transition: opacity 0.35s ease 0.25s, visibility 0s linear 0.25s; }
.handoff-card.trade-reveal.tr-playing .modal-actions { transition: none; }
.tr-empty svg { width: 58%; }

/* === Quick chat (src/ui/chat.js) ======================================================================
   The Chat button beside the Menu button (a match only), its panel of preset lines and emotes under the
   top-right corner, the speech bubbles over the guests (in the tag layer, under the interface), the chat
   lines in the feed, and the end screen's row. Brass line drawings, never emoji. */
.ctl.chat {
  position: relative; overflow: hidden; height: 44px; min-width: 0; padding: 0 13px 0 10px; gap: 6px;
  font-family: var(--serif); font-size: 13px; font-weight: 600; letter-spacing: 0.02em; color: var(--ivory-dim);
  border-radius: 10px; border-color: var(--line);
}
.ctl.chat svg { width: 18px; height: 18px; flex: none; color: var(--brass); }
.ctl.chat[aria-expanded="true"] { background: rgba(40, 32, 14, 0.9); border-color: var(--brass); color: var(--ivory); }
.ctl.chat:disabled { cursor: default; color: var(--muted); }
.ctl.chat:disabled svg { color: var(--brass-dim); }
/* after sending: a thin brass line runs down under the label for the cooldown */
.ctl.chat.cooling::after {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: 6px; height: 1.5px; border-radius: 1px;
  background: var(--brass); transform-origin: left center; animation: chatCool var(--chat-cool, 3000ms) linear forwards;
}
@keyframes chatCool { from { transform: scaleX(1); } to { transform: scaleX(0); } }

#hud > .chat-panel { pointer-events: auto; }
.chat-panel {
  position: absolute; top: calc(var(--safe-top) + 110px); right: calc(var(--safe-right) + 14px);
  width: 300px; max-width: calc(100vw - 28px); padding: 10px 10px 11px; border-radius: 14px;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.55), inset 0 0 0 2px var(--line-soft), 0 10px 26px rgba(0, 0, 0, 0.5);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); animation: chatIn 0.14s ease-out;
}
@keyframes chatIn { from { opacity: 0; } to { opacity: 1; } }
.chat-kicker {
  display: flex; align-items: center; gap: 8px; margin: 1px 2px 8px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brass);
}
.chat-kicker::before, .chat-kicker::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, var(--line)); }
.chat-kicker::after { background: linear-gradient(90deg, var(--line), transparent); }
.chat-phrases { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.chat-phrase {
  appearance: none; min-height: 44px; padding: 6px 10px; border-radius: 9px; text-align: left; cursor: pointer;
  background: rgba(255, 255, 255, 0.035); border: 1px solid var(--line-soft); color: var(--ivory);
  font: 600 14px/1.2 var(--serif); letter-spacing: 0.01em; touch-action: manipulation;
}
.chat-phrase:last-child { grid-column: 1 / -1; text-align: center; }
.chat-phrase:active, .chat-emote:active { background: rgba(201, 162, 78, 0.22); border-color: var(--brass); }
.chat-emotes { display: flex; justify-content: space-between; margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--line-soft); }
.chat-emote {
  appearance: none; width: 44px; height: 44px; padding: 0; border-radius: 50%; cursor: pointer; touch-action: manipulation;
  display: inline-flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 35%, #22252f, #12141b); border: 1px solid var(--line); color: var(--brass-bright);
}
.chat-emote svg { width: 27px; height: 27px; display: block; }

/* A speech bubble over the speaker: its tail points down at their head. (Placed by its top-left corner
   through a transform the script writes, so only opacity is animated here.) */
.chat-bubble {
  display: inline-flex; align-items: center; gap: 6px; margin-top: -8px; padding: 5px 11px 5px 8px; border-radius: 12px;
  background: rgba(16, 18, 26, 0.94); border: 1px solid var(--brass); color: var(--ivory);
  font: 600 14px/1.25 var(--serif); letter-spacing: 0.01em; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  animation: chatIn 0.18s ease-out; transition: opacity 0.3s ease;
}
.chat-bubble::after {
  content: ""; position: absolute; left: 50%; bottom: -6px; width: 10px; height: 10px; margin-left: -5px; transform: rotate(45deg);
  background: rgba(16, 18, 26, 0.94); border-right: 1px solid var(--brass); border-bottom: 1px solid var(--brass);
}
.chat-bubble.mine { border-color: var(--brass-bright); background: rgba(40, 32, 14, 0.94); }
.chat-bubble.mine::after { border-color: var(--brass-bright); background: rgba(40, 32, 14, 0.94); }
.chat-bubble.emote { padding: 3px 9px 3px 7px; }
.chat-bubble.leaving { opacity: 0; }
.chat-bubble .cb-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5); }
.chat-bubble .cb-icon { display: block; color: var(--brass-bright); }
.chat-bubble .cb-icon svg { width: 26px; height: 26px; display: block; }

/* In the feed: "Henry: Good evening!", the name in brass. */
.feed-line.chat .feed-who { color: var(--brass-bright); font-weight: 700; }
.feed-line.chat .feed-icon svg { width: 17px; height: 17px; }

/* The end screen: a one-tap "Good game!" on its own row, and what is said there in the row under it
   (its height kept from the start, so neither the button nor Main menu / Play again moves as lines come). */
.end-chat { display: flex; flex-direction: column; align-items: center; gap: 8px; margin: -8px auto 18px; max-width: min(540px, 80vw); }
.ec-lines { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; min-height: 30px; }
.ec-say {
  appearance: none; position: relative; overflow: hidden; display: inline-flex; align-items: center; gap: 7px; height: 44px; padding: 0 16px 0 12px;
  border-radius: 999px; border: 1px solid var(--line); background: rgba(255, 255, 255, 0.04); color: var(--ivory); cursor: pointer;
  touch-action: manipulation; font: 600 14px/1 var(--serif); letter-spacing: 0.01em;
}
.ec-say:disabled { opacity: 0.5; cursor: default; }
.ec-say.cooling { opacity: 0.75; }
.ec-say.cooling::after {
  content: ""; position: absolute; left: 14px; right: 14px; bottom: 6px; height: 1.5px; border-radius: 1px;
  background: var(--brass); transform-origin: left center; animation: chatCool var(--chat-cool, 3000ms) linear forwards;
}
.ec-line {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px 0 7px; border-radius: 999px;
  background: rgba(14, 16, 22, 0.8); border: 1px solid var(--line-soft); color: var(--ivory-dim); font-size: 13px;
  animation: feedIn 0.35s ease both;
}
.ec-icon { display: inline-flex; color: var(--brass-bright); }
.ec-icon svg { width: 16px; height: 16px; display: block; }
.ec-who { color: var(--brass-bright); font-weight: 700; }

/* Seven Settings rows with Quick chat: the tighter spacing of the Music / Sound block above now applies
   up to 860 px tall (Done stays on screen on a 1024 x 768 iPad); see also the Tips row below. */
@media (max-height: 860px) {
  #menu-settings .menu-h2 { margin-bottom: 10px; font-size: 28px; }
  #menu-settings .menu-field { margin-bottom: 11px; }
  #menu-settings .mf-label { margin-bottom: 6px; }
  #menu-settings .seg-btn { min-height: 44px; }
  #menu-settings .menu-actions { margin-top: 14px; }
}

/* ==== Your record (src/ui/record.js) ===========================================================
   The Your record screen and the quiet record line under the result on the end screen. */
/* Main menu: Your record, under Settings and a step smaller. */
.menu-btn.minor { min-height: 48px; padding: 8px 22px; background: rgba(16, 18, 26, 0.74); border-color: var(--line-soft); }
.menu-btn.minor .mb-main { font-size: 18px; color: var(--ivory-dim); }

/* The Your record screen: played / won / lost in big brass numerals on a framed plate, the win rate
   on a rule beneath them, then the split by side and the escapes as quiet rows. */
.rec-plate {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-radius: 14px; padding-top: 14px;
  background: rgba(16, 18, 26, 0.86); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.55), inset 0 0 0 4px rgba(201, 162, 78, 0.07), 0 10px 28px rgba(0, 0, 0, 0.35);
}
.rec-big { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 0 6px 12px; }
.rec-big + .rec-big { border-left: 1px solid var(--line-soft); }
.rec-num {
  font-family: var(--serif); font-size: 44px; font-weight: 700; line-height: 1; font-variant-numeric: lining-nums tabular-nums;
  background: linear-gradient(180deg, #f6e2a8 0%, #e2bd67 55%, #a8812f 100%); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: var(--brass-bright);
}
.rec-cap { font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--ivory-dim); }
.rec-rate {
  grid-column: 1 / -1; display: flex; align-items: center; justify-content: center; gap: 12px;
  padding: 9px 12px 11px; border-top: 1px solid var(--line-soft);
}
.rec-rate::before, .rec-rate::after { content: ""; flex: 0 1 56px; height: 1px; background: linear-gradient(90deg, transparent, var(--brass)); }
.rec-rate::after { background: linear-gradient(90deg, var(--brass), transparent); }
.rec-rate-label { font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--brass); }
.rec-rate-num { font-family: var(--serif); font-size: 24px; font-weight: 700; line-height: 1; color: var(--brass-bright); }
.rec-rows { margin-top: 10px; }
.rec-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 8px 4px;
  border-bottom: 1px solid var(--line-soft);
}
.rec-label { font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ivory-dim); white-space: nowrap; }
.rec-val { font-family: var(--serif); font-size: 16px; font-weight: 700; color: var(--ivory); text-align: right; white-space: nowrap; }
#rec-note { margin-top: 10px; }
#menu-record .menu-actions { margin-top: 16px; }
.rec-confirm-text { margin: 16px 0 0; font-family: var(--serif); font-size: 17px; line-height: 1.4; color: var(--ivory); text-wrap: pretty; }
.menu-btn.rec-danger { background: linear-gradient(180deg, #4a1220, #2b0a13); border-color: var(--poss-line); color: var(--ivory); }

/* The end screen: your record after this game, one quiet line under the result. */
#end-overlay .card p.end-record { margin: -12px 0 18px; font-family: var(--serif); font-style: italic; font-size: 15px; letter-spacing: 0.02em; color: var(--brass); }
/* an achievement the match earned (src/ui/honoursEnd.js), as quiet as the record line above it */
#end-overlay .card p.end-honours { margin: -12px 0 18px; font-family: var(--serif); font-style: italic; font-size: 15px; letter-spacing: 0.02em; color: var(--brass-bright); }

/* === Soul cards and known allies (src/ui/soulFace.js, tradeReveal.js, allies.js) =====================
   Every Possession card is its owner's own soul, with their face in its mirror (one drawn image, so the
   card surfaces need nothing new). In the trade scenes a SPENT soul burns out in crimson (no grey ash),
   two souls of your own rise when you are possessed, and two souls handed over at once meet in the
   middle. Known allies' red eyes are the possessed portrait itself; nothing else changes on the strip. */
.tr-rail.go-meet-r { animation: tr-meet-r 0.75s cubic-bezier(0.45, 0, 0.3, 1) both; }
.tr-rail.go-meet-l { animation: tr-meet-l 0.75s cubic-bezier(0.45, 0, 0.3, 1) both; }
.tr-tilt.lean-a { animation: tr-lean-a 0.75s ease-in-out both; }
.tr-tilt.lean-b { animation: tr-lean-b 0.75s ease-in-out both; }
@keyframes tr-meet-r { 0% { transform: translate(0, 0); } 60% { transform: translate(11%, -5%); } 100% { transform: translate(13.5%, 0); } }
@keyframes tr-meet-l { 0% { transform: translate(0, 0); } 60% { transform: translate(-11%, -5%); } 100% { transform: translate(-13.5%, 0); } }
@keyframes tr-lean-a { from { transform: rotate(0deg); } to { transform: rotate(-7deg); } }
@keyframes tr-lean-b { from { transform: rotate(0deg); } to { transform: rotate(7deg); } }
/* A spent soul: no ash pile, only a faint crimson glow where it was; without particles it fades crimson. */
.tr-card.soul-burn .tr-ash { background: radial-gradient(50% 50% at 50% 55%, rgba(163,38,58,0.3), rgba(96,14,34,0.14) 55%, rgba(60,8,20,0) 100%); }
.tr-card.soul-burn.burnt .tr-ash { opacity: 0; transition: opacity 1.4s ease 0.4s; }
.tr-card.fade-burn.soul-burn .tr-front { animation: tr-fade-soul 0.5s ease-in forwards; }
@keyframes tr-fade-soul { 0% { opacity: 1; filter: none; } 40% { opacity: 1; filter: brightness(1.3) saturate(1.6) hue-rotate(-30deg); } 100% { opacity: 0; filter: brightness(0.4) saturate(2); } }
/* Your two new souls rise out of the smoke, a little apart (their places are set by the script). */
.tr-card.tr-extra {
  transform: translate(var(--fan-x), 12%) scale(0.86); transform-origin: 50% 88%;
  transition: transform 0.6s cubic-bezier(0.2, 0.8, 0.25, 1), opacity 0.45s ease;
}
.tr-card.tr-extra.fanned { transform: translate(var(--fan-x), -2%) rotate(var(--fan-r)); }

/* === First-match tips (src/ui/tips.js; the words: src/data/tips.js) ===================================
   A small Art Deco card beside the thing it explains: deep navy, a brass edge with a fine inner rule, a
   serif title, ivory words, a quiet "Hide tips" and "Got it", a little brass arrow towards what it
   explains, and a thin brass line that runs down while it waits. Over the interface, and beside an open
   meeting (z-index 20: above the overlays' scrim at 10, under the main menu at 40 and the black fade at
   90). Only the card itself takes taps. No sound, no glow, nothing that blinks. */
.tip {
  position: fixed; left: 0; top: 0; z-index: 20;
  width: 262px; max-width: calc(100vw - 20px); padding: 9px 14px 13px; border-radius: 12px;
  background: linear-gradient(180deg, #1a1e2d 0%, #11141e 100%);
  border: 1px solid var(--brass);
  box-shadow: inset 0 0 0 3px #141824, inset 0 0 0 4px var(--line-soft), 0 12px 28px rgba(0, 0, 0, 0.55);
  color: var(--ivory); text-align: left; pointer-events: auto; touch-action: manipulation;
}
.tip[hidden] { display: none; }
.tip.moving { transition: translate 0.25s ease; }   /* (placed by translate: src/ui/tips.js setAt) */
.tip.in { animation: tipIn 0.24s ease-out; }
@keyframes tipIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
.tip-kicker {
  display: flex; align-items: center; gap: 8px; margin: 0 0 3px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.2em; text-transform: uppercase; color: var(--brass);
}
.tip-kicker::before, .tip-kicker::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, transparent, var(--line)); }
.tip-kicker::after { background: linear-gradient(90deg, var(--line), transparent); }
.tip-title { font-family: var(--serif); font-size: 17px; font-weight: 700; line-height: 1.2; letter-spacing: 0.01em; color: var(--brass-bright); }
.tip-text { margin: 4px 0 9px; font-size: 14px; line-height: 1.42; color: var(--ivory); text-wrap: pretty; }
.tip-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.tip-actions[hidden] { display: none; }
.tip-ok {
  appearance: none; min-height: 44px; min-width: 88px; padding: 6px 16px; border-radius: 9px; cursor: pointer;
  background: rgba(201, 162, 78, 0.16); border: 1px solid var(--brass); color: var(--brass-bright);
  font: 700 14px/1 var(--serif); letter-spacing: 0.02em;
}
.tip-ok:active { background: rgba(201, 162, 78, 0.32); }
.tip-hide {
  appearance: none; min-height: 44px; padding: 6px 4px 6px 2px; border: 0; background: none; cursor: pointer;
  color: var(--muted); font: 600 12.5px/1 var(--sans); letter-spacing: 0.02em;
  text-decoration: underline; text-decoration-color: rgba(168, 158, 138, 0.45); text-underline-offset: 3px;
}
.tip-hide:active { color: var(--ivory-dim); }
/* the arrow: a small brass-edged diamond on the side facing what the tip explains (--tip-arrow: where) */
.tip-arrow { position: absolute; width: 11px; height: 11px; border: 1px solid var(--brass); transform: rotate(45deg); pointer-events: none; }
.tip[data-side="above"] .tip-arrow { left: calc(var(--tip-arrow, 50%) - 6px); bottom: -7px; background: #11141e; border-left: 0; border-top: 0; }
.tip[data-side="below"] .tip-arrow { left: calc(var(--tip-arrow, 50%) - 6px); top: -7px; background: #1a1e2d; border-right: 0; border-bottom: 0; }
.tip[data-side="left"] .tip-arrow { top: calc(var(--tip-arrow, 50%) - 6px); right: -7px; background: #161a26; border-left: 0; border-bottom: 0; }
.tip[data-side="right"] .tip-arrow { top: calc(var(--tip-arrow, 50%) - 6px); left: -7px; background: #161a26; border-right: 0; border-top: 0; }
/* the time it has left on screen */
.tip-time {
  position: absolute; left: 16px; right: 16px; bottom: 5px; height: 1.5px; border-radius: 1px;
  background: var(--brass-dim); transform-origin: left center; pointer-events: none;
}
.tip.in .tip-time { animation: tipTime var(--tip-ms, 9000ms) linear forwards; }
@keyframes tipTime { from { transform: scaleX(1); } to { transform: scaleX(0); } }
/* after Hide tips: a moment of "Tips are off" */
.tip.bye .tip-title { color: var(--ivory-dim); }
.tip.bye .tip-text { margin-bottom: 2px; color: var(--ivory-dim); }
.tip.bye .tip-time { display: none; }
@media (prefers-reduced-motion: reduce) { .tip.in { animation: none; } .tip.moving { transition: none; } }

/* Settings > Tips: On / Off and "Show tips again" share one row. */
.tips-row { display: flex; gap: 6px; }
.tips-row #set-tips { flex: 2 1 0; min-width: 0; }
.tips-row .tips-again { flex: 1.3 1 0; color: var(--brass); font-size: 15px; }
.tips-row .tips-again:disabled { color: var(--muted); opacity: 0.6; cursor: default; }
/* Eight Settings rows with Tips: the spacing between them tightens a little more on a short screen, so
   the panel keeps clear of the screen's edges (1024 x 768, and 1024 x 690 with Safari's bars). The
   buttons keep their size. */
@media (max-height: 860px) {
  #menu-settings .menu-h2 { margin-bottom: 8px; }
  #menu-settings .menu-field { margin-bottom: 8px; }
  #menu-settings .mf-label { margin-bottom: 5px; }
  #menu-settings .menu-actions { margin-top: 12px; }
}
@media (max-height: 720px) {
  #menu-settings .menu-kicker { margin-bottom: 4px; }
  #menu-settings .menu-h2 { margin-bottom: 6px; font-size: 26px; }
  #menu-settings .menu-field { margin-bottom: 6px; }
  #menu-settings .mf-label { margin-bottom: 4px; }
  #menu-settings .menu-actions { margin-top: 10px; }
  #menu-settings .menu-btn.small { min-height: 50px; }
}
@media (max-height: 700px) {   /* (Safari with its bars: the buttons stay 44 px tall, the spacing gives instead) */
  #menu-settings .menu-field { margin-bottom: 5px; }
  #menu-settings .mf-label { margin-bottom: 3px; }
}
/* Settings > Quick chat and Clearer possessed eyes: two On / Off rows side by side, so the panel is no taller; the
   one-line note under them only where the screen has room (a screen reader reads it with the row everywhere). */
.menu-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.menu-pair .menu-field { min-width: 0; }
.menu-pair .mf-label { white-space: nowrap; letter-spacing: 0.1em; }
#menu-settings .set-pair-note { margin: -2px 0 10px; font-size: 13px; line-height: 1.35; min-height: 0; }
@media (max-height: 800px) { #menu-settings .set-pair-note { display: none; } }

/* ==== Profiles: the register, the profile card and usernames at the table ========================
   (src/ui/register.js, src/ui/profileCard.js, src/ui/menu.js; the caps on long usernames in the guest
   strip, the player panel and End turn: src/hud.js) */
/* The register (first run, and Change name): anchored to the TOP of the screen, not centred, so the name
   field and both buttons stay above the iPad's on-screen keyboard (about 400 px in landscape). */
.menu.signup .menu-panel { top: max(28px, calc(var(--safe-top) + 22px)); transform: none; }
.menu.signup.leaving .menu-panel { transform: translateX(-24px); }
.menu.snap .menu-panel { transition: none; }   /* (to and from the register: no slide across the screen) */
#menu-signup .menu-h2 { margin-bottom: 14px; }
.su-form { margin: 0; }
.su-field { position: relative; }
.su-input {
  box-sizing: border-box; width: 100%; height: 56px; padding: 0 64px 0 16px; border-radius: 12px;
  background: rgba(10, 12, 18, 0.9); border: 1.5px solid var(--line); color: var(--ivory);
  font: 600 22px/1 var(--serif); letter-spacing: 0.02em;   /* 16 px or more: Safari does not zoom in on focus */
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.5); outline: none; -webkit-appearance: none; appearance: none;
}
.su-input::placeholder { color: rgba(202, 191, 168, 0.38); font-style: italic; font-weight: 400; }
.su-input:focus { border-color: var(--brass-bright); box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.5), 0 0 0 3px rgba(201, 162, 78, 0.22); }
.su-input.bad { border-color: var(--poss-line); }
.su-count { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); font-size: 12px; color: var(--muted); pointer-events: none; }
.su-hint { margin-top: 8px; min-height: 1.4em; font-size: 14px; line-height: 1.4; color: var(--muted); }
.su-hint.bad { color: #eaa898; }
#menu-signup .menu-actions { margin-top: 14px; }
.su-device { margin-top: 12px; font-size: 13px; line-height: 1.45; color: var(--muted); text-wrap: pretty; }
.su-device.su-private { color: var(--brass-bright); }

/* The profile card: under the tagline; the whole card is one button that opens your avatar. Portrait 3:4
   (the portraits' own shape), the username in the serif (a long one ends in "…"), a brass link line. */
.profile-card {
  appearance: none; display: flex; align-items: center; gap: 14px; width: 100%; box-sizing: border-box;
  min-height: 84px; padding: 8px 16px 8px 8px; margin: 0 0 14px; border-radius: 14px; cursor: pointer; text-align: left;
  background: rgba(16, 18, 26, 0.86); border: 1px solid var(--line); color: var(--ivory); font: inherit;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5), 0 10px 28px rgba(0, 0, 0, 0.35);
  transition: transform 0.12s ease, border-color 0.2s ease;
}
.profile-card[hidden] { display: none; }
.profile-card:active { transform: scale(0.98); }
.pc-portrait { flex: none; width: 54px; height: 72px; border-radius: 10px; overflow: hidden; border: 1px solid var(--brass); background: var(--panel-solid); }
.pc-portrait img, .pc-portrait svg { width: 100%; height: 100%; object-fit: cover; display: block; -webkit-user-drag: none; }
.pc-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.pc-kicker { font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }
.pc-name { font-family: var(--serif); font-size: clamp(18px, 2.2vw, 24px); font-weight: 700; color: var(--ivory); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pc-edit { font-size: 13.5px; font-weight: 600; color: var(--brass); letter-spacing: 0.02em; }
#menu-main .menu-tag { margin-bottom: 18px; }
/* Settings and Your record share one row under the two ways to play. */
.menu-row2 { display: flex; gap: 12px; }
.menu-row2 .menu-btn { flex: 1 1 0; min-width: 0; min-height: 52px; align-items: center; }
.menu-row2 .menu-btn .mb-main { font-size: 19px; }

/* Usernames at the table: one line in the guest strip (a little smaller, in the sans), and caps so a
   long name never stretches the bottom bar (the player panel, End turn's "nightowl's turn"). */
.mini-name.u { font-family: var(--sans); font-size: 12px; font-weight: 700; letter-spacing: 0.01em; }
.player-panel .player-name { max-width: 200px; }
.btn.end .end-name { display: inline-block; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
/* The matchmaking list: every seat by username; yours marked "You". */
.mm-seat.you .mm-guest { color: var(--brass-bright); font-weight: 700; letter-spacing: 0.04em; }
/* The feed: a long username breaks onto the next line instead of running out of its box. */
.feed-line, .feed-text { overflow-wrap: anywhere; }

/* ==== The wardrobe (#menu-avatar) and the Hotel Honours page: their own stylesheet, wardrobe.css ==== */

/* === Quick chat: two tabs of lines and "Choose a guest" (src/ui/chat.js) =================================
   The panel (320 px) has two tabs, "Table" and "Suspicion", of ten lines each (two columns of five, 44 px
   rows), the emotes under them. A line that names a guest shows a dotted brass blank where the name goes
   and a chevron: tapping it turns the panel to the second step (Back, the line, "Choose a guest", a tile
   for each guest still in the hotel), at the same height, so nothing jumps. In a bubble and in the feed the
   guest a line names is in bright brass; a line that names YOU gets a doubled bright-brass edge (never
   crimson: that is only ever your own possessed look, and a public line must not look like a role). */
.chat-panel.cp { width: 320px; padding: 8px 10px 10px; }
.cp-tabs { display: grid; grid-template-columns: 1fr 1fr; margin: 0 0 8px; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.cp-tab {
  appearance: none; height: 44px; border: 0; background: transparent; color: var(--ivory-dim); cursor: pointer;
  font: 700 12.5px/1 var(--sans); letter-spacing: 0.14em; text-transform: uppercase; touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.cp-tab + .cp-tab { border-left: 1px solid var(--line); }
.cp-tab[aria-selected="true"] { background: rgba(201, 162, 78, 0.16); color: var(--brass-bright); box-shadow: inset 0 -2px 0 var(--brass); }
.cp-page { display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: 44px; gap: 6px; min-height: calc(5 * 44px + 4 * 6px); align-content: start; }
.cp-page[hidden], .cp-whom[hidden], .cp-main[hidden] { display: none; }
.cp-page .chat-phrase { min-height: 0; height: 44px; padding: 4px 9px; font-size: 13.5px; line-height: 1.12; display: flex; align-items: center; }
.cp-page .chat-phrase:last-child { grid-column: auto; text-align: left; }
.cp-label { display: block; }
.chat-phrase:disabled { opacity: 0.4; cursor: default; }
/* a line about a guest: the blank where their name goes, and a chevron (a second step follows) */
.chat-phrase.about { position: relative; padding-right: 20px; }
.chat-phrase.about::after {
  content: ""; position: absolute; right: 9px; top: 50%; width: 6px; height: 6px; margin-top: -4px;
  border-right: 1.5px solid var(--brass); border-bottom: 1.5px solid var(--brass); transform: rotate(-45deg);
}
.cp-blank {
  /* (no space after it: "I trust WHO." — the right margin also takes back the last letter's spacing) */
  display: inline-block; min-width: 26px; margin: 0 -0.12em 0 1px; padding: 0 0 0 2px; border-bottom: 1.5px dotted var(--brass);
  color: var(--brass-bright); font: 700 12px/1.5 var(--sans); letter-spacing: 0.1em; text-transform: uppercase; vertical-align: 0;
}
/* the second step: Back, the line, "Choose a guest", the guests */
.cp-whom-head { display: flex; align-items: center; gap: 8px; height: 44px; margin: 0 0 8px; }
.cp-back {
  appearance: none; flex: none; width: 44px; height: 44px; border-radius: 10px; border: 1px solid var(--line); cursor: pointer;
  background: rgba(255, 255, 255, 0.035); color: var(--brass-bright); display: inline-flex; align-items: center; justify-content: center;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.cp-back svg { width: 18px; height: 18px; }
.cp-back:active { background: rgba(201, 162, 78, 0.22); border-color: var(--brass); }
.cp-whom-line { font: 600 15px/1.2 var(--serif); color: var(--ivory); min-width: 0; }
.cp-whom-hint { margin: 0 2px 8px; font-size: 11.5px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brass); }
.cp-guests { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 92px; gap: 6px; align-content: start; }
.cp-guest {
  appearance: none; min-width: 0; height: 92px; padding: 6px 4px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--line-soft); background: rgba(255, 255, 255, 0.035);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.cp-guest:active { background: rgba(201, 162, 78, 0.22); border-color: var(--brass); }
.cp-guest .cp-portrait { width: 52px; height: 52px; border-radius: 10px; flex: none; }
.cp-guest-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 600 13px/1.1 var(--serif); color: var(--ivory); }
/* the guest a line names, in a bubble, the feed and the end screen */
.chat-bubble .cb-name, .feed-line .feed-name, .ec-line .ec-name { color: var(--brass-bright); font-weight: 700; }
.chat-bubble.about-me { border-color: var(--brass-bright); box-shadow: 0 0 0 1px var(--brass-bright), 0 4px 14px rgba(0, 0, 0, 0.5); }
.chat-bubble.about-me::after { border-color: var(--brass-bright); }
.feed-line .feed-name.you, .ec-line .ec-name.you { color: var(--ivory); text-decoration: underline; text-decoration-color: var(--brass-bright); text-underline-offset: 3px; }
.ec-line.me { color: var(--ivory); border-color: var(--line); }

/* ==== Start-up, the problem card, the version line (reliability round, 14 Oct 2026) ================================
   index.html: #boot (what is loading), #error-overlay (the problem card), the two "turn sideways" messages;
   the Version line at the bottom of Settings. */
/* What is loading: away for the first moment (a quick load shows nothing at all), gone the instant the menu or a
   direct link's "Tap to begin" card shows (the sibling rules), and under every screen, the cards included. */
.boot {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 5; display: flex; align-items: center; justify-content: center;
  pointer-events: none; opacity: 0; animation: boot-in 0.5s ease 0.9s forwards;
}
.boot[hidden], #menu:not([hidden]) ~ .boot, #start-overlay:not([hidden]) ~ .boot { display: none; }
.boot-card { padding: 0 24px; text-align: center; }
.boot-title { font-family: var(--serif); font-size: clamp(28px, 5vw, 44px); font-weight: 700; letter-spacing: 0.01em; color: var(--ivory); }
.boot-text { margin-top: 10px; font-size: 15px; letter-spacing: 0.04em; color: var(--ivory-dim); }
.boot-count { margin-top: 6px; min-height: 1.3em; font-size: 12.5px; letter-spacing: 0.04em; color: var(--muted); }
.menu-loading .boot-count { display: inline; margin: 0; min-height: 0; font-size: inherit; }
@keyframes boot-in { to { opacity: 1; } }
/* The problem card (could not load / went wrong): above the menu, the black fade and the game; only the
   "turn sideways" card (z-index 200) is above it. The small print is for a screenshot. */
#error-overlay { top: 0; right: 0; bottom: 0; left: 0; z-index: 150; }
.error-card { max-width: min(480px, 92vw); }
.error-card p { margin-bottom: 18px; }
.error-actions { margin-top: 4px; }
.error-actions .btn[hidden] { display: none; }
.error-card .error-detail {
  margin: 20px 0 0; font-size: 12px; line-height: 1.4; color: var(--muted); opacity: 0.9; overflow-wrap: anywhere;
  -webkit-user-select: text; user-select: text;
}
.error-card .error-detail[hidden] { display: none; }
/* "Turn sideways" (taller than wide) or "Make this window wider" (wide but small: Split View, Page Zoom). */
.rotate-wide { display: none; }
@media (orientation: landscape) {
  .rotate-tall { display: none; }
  .rotate-wide { display: block; }
}
@media (max-height: 420px) { .rotate-icon { display: none; } }
/* Settings > Version: quiet, at the bottom. */
.set-version { margin-top: 10px; text-align: center; font-size: 12px; line-height: 1.2; letter-spacing: 0.05em; color: var(--muted); }

/* ==== Round 1, build fixes (accidental taps, found card and legend at 1024x694, Reduce Motion) ==== */

/* The card pick (src/ui/handoff.js privatePick): a tap lifts the card; under the row, its name and what it
   does (two lines kept free, so choosing a card never moves the buttons); the gold button gives it. */
.offer-block .card-tile.selectable { transition: transform 0.12s ease; }
.offer-block .card-tile.selected { transform: translateY(-6px); }
.offer-summary.card-desc { min-height: 2.9em; margin-top: 10px; line-height: 1.4; color: var(--ivory); text-wrap: balance; }
.offer-summary.card-desc b { color: var(--brass-bright); margin-right: 4px; }
/* A one-card find at a short window (an iPad with Safari's bars: 1024x694): the note ("You now hold 2
   Lanterns.") sat behind the Add to my hand bar and had to be scrolled to. The card picture shrinks with
   the height instead, the card's padding is a little tighter, and the bar sits under the note, so nothing
   is hidden and nothing needs scrolling. Taller windows keep the big card. */
@media (max-height: 770px) {
  .handoff-card.found { padding-top: 16px; padding-bottom: 16px; }
  .handoff-card.found .modal-actions { bottom: -16px; margin-top: 10px; padding-top: 8px; }
  .handoff-card.found .handoff-found { margin: 2px auto 6px; }
  .handoff-found .big-card { width: clamp(130px, min(24vw, calc((92vh - 350px) / 1.5)), 250px); }
  .handoff-found.pair .big-card { width: clamp(120px, min(21vw, calc((92vh - 390px) / 1.5)), 220px); }
}

/* The map's legend: the canvas may shrink to the panel (it used to keep the size it was last drawn at, which
   pushed the legend's last row, the Barricade, out of the panel at 1024x694), and at a short window the legend
   sits in tighter rows. */
#map-canvas { min-height: 0; }
@media (max-height: 770px) {
  .map-legend { gap: 4px 14px; padding: 6px 16px; }
}
/* Reduce Motion (the iPad's Settings > Accessibility > Motion; src/motion.js): the motion that is only
   decoration stops, and everything it showed is still shown. The trade and attack scenes and the tips had
   their own rules already (above); the flicker of the two spooky corridors holds steady in
   src/render/flicker.js; the lobby behind the menu is held Still in src/settings.js. */
@media (prefers-reduced-motion: reduce) {
  .fan-card.dealt { animation-duration: 0.01s; animation-delay: 0s; }       /* (the card is in its place at once; the class still clears) */
  .search-spot.live .ss-badge { animation: none; }                          /* the search icon's pulse */
  .think-dots i { animation: none; opacity: 0.8; transform: none; }         /* the waiting dots: three still dots */
  .mm-seat.empty .mm-name { animation: none; opacity: 0.7; }                /* "waiting for a guest" */
  .mm-seat.joined, .menu-screen, .handoff-found .big-card, .cv-panel,
  .confirm-bar, .toast, .feed-line { animation: none; }                     /* things sliding or dealing in */
  #view canvas { transition: none; }                                        /* the menu's blur and slow zoom */
  .menu-panel { transition: opacity 0.3s ease; }
  .menu.leaving .menu-panel { transform: translateY(-50%); }                /* (it fades out, it does not slide) */
}
/* (END of the round 1 build-fixes block: keep this line last; new rules above it) */

/* ==== Round 1, fixer block: Reduce Motion in Settings, the loading screen's way out, the wider message ==== */

/* Settings > Menu background with the iPad's Reduce Motion on: Animated is dimmed and cannot be tapped, and the
   label says why (on the same line, so the Settings screen stays as tall as before). */
#set-menuMotion .seg-btn:disabled { opacity: 0.4; cursor: default; }
.mf-why { margin-left: 10px; font-weight: 400; letter-spacing: 0.02em; text-transform: none; color: var(--muted); }
.mf-why[hidden] { display: none; }

/* The loading screen's way out: a plain Reload button, which the start-up script (index.html) shows only when
   nothing new has loaded for 30 seconds. (.boot lets taps through to the page below; the button takes its own.) */
.boot-reload { margin-top: 18px; pointer-events: auto; }
.boot-reload[hidden] { display: none; }

/* "Turn sideways" is for a device that is held upright. A window taller than wide on a device that is already held
   sideways (Split View, Slide Over; the start-up script sets html.device-landscape) is asked for more room instead. */
@media (orientation: portrait) {
  html.device-landscape .rotate-tall { display: none; }
  html.device-landscape .rotate-wide { display: block; }
}

/* ==== Round 2, build-learn: How to play, the Menu panel, the Lanterns chip, the role screen, the end screen ====
   (src/ui/howToPlay.js, src/ui/gameMenu.js, src/hud.js, src/ui/handoff.js, src/overlays.js; the words: src/data/) */

/* Main menu: How to play and Cards share a row, Settings and Your record the one under it (the rows are the
   .menu-row2 of the main menu, round 1); a hint for a player who has played nothing yet sits just under Practice alone. */
.menu-hint { margin: -5px 4px 0; font-family: var(--serif); font-style: italic; font-size: 14.5px; line-height: 1.35; color: var(--brass); text-wrap: pretty; }
.menu-hint[hidden] { display: none; }

/* A keyboard user sees where they are (a finger never does: these show only for :focus-visible). */
.howto .btn:focus-visible, .gamemenu .btn:focus-visible, .gamemenu .seg-btn:focus-visible { outline: 2px solid var(--brass-bright); outline-offset: 2px; }

/* How to play: above the menu (40) and the Menu panel, under the problem card. Five pages; a page never needs
   more than the screen, but if a window is very short the lines scroll inside the card (the buttons stay put). */
.howto { position: fixed; z-index: 60; background: rgba(6, 7, 11, 0.86); }
.howto-card { width: min(660px, 94vw); max-height: 94vh; display: flex; flex-direction: column; padding: 22px 30px 18px; text-align: left; }
.howto-kicker { text-align: center; font-family: var(--serif); font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; color: var(--brass); margin-bottom: 6px; }
.howto-card h1 { text-align: center; margin: 0 0 12px; font-size: clamp(26px, 4vw, 34px); color: var(--brass-bright); }
.howto-lines { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; flex: 1 1 auto; min-height: 0; overflow-y: auto; touch-action: pan-y; }
.howto-lines li { position: relative; padding-left: 22px; font-size: 16.5px; line-height: 1.45; color: var(--ivory); text-wrap: pretty; }
.howto-lines li::before { content: '\25C6'; position: absolute; left: 0; top: 0.12em; font-size: 11px; color: var(--brass); }
.howto-dots { display: flex; gap: 8px; justify-content: center; margin: 14px 0 12px; }
.howto-dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.14); border: 1px solid var(--line-soft); }
.howto-dot.on { background: var(--brass); border-color: var(--brass-bright); box-shadow: 0 0 6px rgba(201, 162, 78, 0.5); }
.howto-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.howto-nav { display: flex; gap: 12px; }
.howto-actions .btn.big { font-size: 18px; padding: 10px 26px; min-height: 52px; }
.howto-actions .btn:disabled { opacity: 0.4; }

/* The in-match Menu panel: Resume (gold, the safe way on), the two sound rows, How to play and Leave. */
.gamemenu { z-index: 12; }
.gamemenu-card { width: min(470px, 94vw); padding: 22px 28px 24px; }
.gamemenu-card .notice-rule { margin-bottom: 12px; }
.gamemenu-card h1 { margin: 0 0 14px; font-size: clamp(26px, 4vw, 34px); }
.gm-field { text-align: left; margin-bottom: 14px; }
.gm-field .mf-label { margin-bottom: 7px; }
.gm-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 18px; }
.gm-actions .btn.big { width: 100%; font-size: 18px; padding: 10px 14px; min-height: 54px; }
.gm-actions .btn.primary { grid-column: 1 / -1; }

/* The Lanterns chip in the player panel: your own count out of the number that opens the Fire Exit. The same for
   everyone (a possessed guest can hold Lanterns too), so it says nothing about a side. */
.lantern-stat { display: flex; margin: -1px 0 -2px; }
.lantern-chip {
  display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 11px 0 8px; border-radius: 999px;
  background: rgba(201, 162, 78, 0.13); border: 1px solid var(--brass-dim); white-space: nowrap;
}
.lantern-chip .lc-glyph { font-size: 13px; line-height: 1; color: #ffd66b; }
.lantern-chip .lc-label { font-size: 11px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ivory-dim); }
.lantern-chip .lc-count { font-size: 14px; font-weight: 800; color: var(--brass-bright); font-variant-numeric: tabular-nums; }

/* The role screen: the paragraph at 16 px (it was 13), and ONE line below it about how the other side wins. */
.role-badge .role-line { font-size: 16px; line-height: 1.5; color: var(--ivory); }
.role-badge.evil .role-line { color: var(--ivory); }
.role-badge .role-other { align-self: stretch; margin-top: 2px; padding-top: 8px; border-top: 1px solid var(--line-soft); font-size: 15px; line-height: 1.45; color: var(--ivory-dim); }
.role-badge.with-portrait .role-other { align-self: stretch; }

/* The end screen: "Victory" or "Defeat" for your side above the title, and the recap line under the summary. */
.end-verdict { margin: 0 0 2px; font-family: var(--serif); font-size: 22px; font-weight: 700; letter-spacing: 0.32em; padding-left: 0.32em; text-transform: uppercase; color: var(--ivory-dim); }
.end-verdict[hidden] { display: none; }
#end-overlay.won .end-verdict { color: var(--brass-bright); }
#end-overlay.lost .end-verdict { color: #eaa898; }
#end-overlay .card p.end-recap { margin: -10px auto 18px; max-width: min(540px, 80vw); font-family: var(--serif); font-size: 15.5px; line-height: 1.4; color: var(--ivory); }
#end-overlay .card p.end-recap[hidden] { display: none; }
@media (max-height: 720px) {      /* (1024 x 694 with Safari's bars: six guests, the recap and the chat row still fit with room to spare) */
  #end-overlay .card { padding-top: 20px; padding-bottom: 20px; }
  .end-verdict { font-size: 19px; }
  #end-overlay .card h1 { font-size: 34px; }
}

/* ==== Round 2, polish block (audit G5, G7, G12): small text, guests easier to tell apart, keyboard focus and tall
   pop-ups. The text sizes themselves were changed in place above; these are the new rules. ==== */

/* The guest's initial in a corner of their portrait in the top strip (src/hud.js sets data-mark; the colour is the
   seat's, so the strip does not rely on colour alone). Drawn by CSS so it survives the portrait being swapped. */
.mini-portrait[data-mark]::before {
  content: attr(data-mark); content: attr(data-mark) / "";      /* (the second: no alternative text, so a screen reader does not read the initial as well as the name; a browser without it keeps the first) */
  position: absolute; left: 3px; top: 3px; z-index: 1;
  display: flex; align-items: center; justify-content: center; box-sizing: border-box;
  min-width: 19px; height: 19px; padding: 0 4px; border-radius: 10px;
  background: var(--player-color); color: #16110a; font: 800 12px/1 var(--sans); letter-spacing: 0;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6);
}

/* The notice card also shows over the main menu (the one that says a match was cut short: src/main.js noteLostMatch),
   so it sits above the menu (z-index 40) and under the black fade (90). In a game nothing else is at that height. */
#notice-overlay { z-index: 45; }

/* A card that can be chosen can be reached with the keyboard (src/ui/cards.js): a clear ring on it. */
.card-tile.selectable:focus-visible { outline: 3px solid var(--brass-bright); outline-offset: 3px; }
.card-tile.selectable:focus:not(:focus-visible) { outline: none; }
/* The box that holds the focus when nothing in it can (src/ui/focus.js): no ring on the box itself. */
.overlay [role="dialog"][tabindex="-1"]:focus, .overlay [role="alertdialog"][tabindex="-1"]:focus,
.cv-panel:focus, .map-panel:focus { outline: none; }

/* Tall pop-ups scroll by touch (index.html data-scrolls; src/input.js lets a finger move inside them): the scroll
   stays inside the pop-up and never pulls the page. */
.modal, .handoff-card, .hand-detail { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

/* The discard screen with a big hand (src/ui/discard.js: more than 8 cards): smaller cards, six to a row, so 11
   cards fit without scrolling on the shortest iPad window (1024x694). */
#discard-cards.dense { gap: 8px; }
#discard-cards.dense .card-tile { width: 84px; }
#discard-cards.dense .card-tile .art { min-height: 54px; }

/* ==== Round 2, fixer ==== */

/* The Lantern's second sentence on the card pick (src/ui/handoff.js privatePick): its own line under the card's words. */
.offer-summary.card-desc .pick-note { display: block; margin-top: 4px; color: var(--brass-bright); }
/* (room for it from the start, whichever card is lifted: choosing a card never moves the Give button) */
.offer-summary.card-desc.with-note { min-height: calc(2.9em + 4px); }

/* ==== Round 4, learn: the Cards screen, and the Cards buttons (src/ui/cardsGuide.js, src/ui/howToPlay.js, src/ui/gameMenu.js) ====
   Every kind of card with its face, its name and one short line; read-only. It opens above How to play (60), the Menu
   panel (12) and the main menu (40), and under the black fade (90). Eleven cards are three columns of four rows; on a short
   window the list scrolls inside the card (the Close button stays put). */
.cardsguide { position: fixed; z-index: 62; background: rgba(6, 7, 11, 0.86); }
.cardsguide-card { width: min(900px, 94vw); max-height: 94vh; display: flex; flex-direction: column; padding: 20px 30px 18px; text-align: left; }
.cardsguide-card h1 { text-align: center; margin: 0 0 12px; font-size: clamp(26px, 4vw, 34px); color: var(--brass-bright); }
.cardsguide-list {
  list-style: none; margin: 0; padding: 2px 4px 6px; flex: 1 1 auto; min-height: 0; overflow-y: auto; touch-action: pan-y;
  overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px 22px; align-content: start;
}
.cardsguide-list:focus-visible, .cardsguide .btn:focus-visible { outline: 2px solid var(--brass-bright); outline-offset: 2px; }
.cg-item { display: flex; align-items: flex-start; gap: 13px; min-width: 0; }
.cg-item .card-tile { width: 66px; flex: none; pointer-events: none; }
.cg-item .card-tile:not(.face) .art { height: 70px; }
.cg-words { min-width: 0; padding-top: 4px; }
.cg-name { font-family: var(--serif); font-weight: 700; font-size: 18px; line-height: 1.15; color: var(--brass-bright); margin-bottom: 3px; }
.cg-desc { font-size: 14.5px; line-height: 1.35; color: var(--ivory); text-wrap: pretty; }
.cg-item[data-type="possession"] .cg-name { color: var(--evil); }
.cardsguide-actions { display: flex; justify-content: center; margin-top: 14px; }
.cardsguide-actions .btn.big { font-size: 18px; padding: 10px 40px; min-height: 52px; }

/* The small Cards button under the last How to play page's lines (no bullet, a touch target of 44 px or more). */
.howto-lines li.howto-more { padding-left: 0; margin-top: 2px; }
.howto-lines li.howto-more::before { content: none; }
.howto-more .btn { font-size: 17px; font-family: var(--serif); font-weight: 700; padding: 8px 26px; min-height: 46px; }

/* The Menu panel with Cards: Resume across the top, How to play and Cards side by side, Leave across the bottom. */
.gm-actions #btn-gm-leave { grid-column: 1 / -1; }

/* ==== Round 4, turn flow (src/ui/discard.js, src/ui/handoff.js privateFound, src/main.js auto end turn) ==== */

/* The found-card reveal: one column per KIND of card (two Lanterns share one), its card or cards large and
   under them the name and one short line, said once. The second column's card comes in a beat after the first. */
.handoff-found .found-type { display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 0; }
.handoff-found .found-faces { display: flex; justify-content: center; gap: 14px; min-width: 0; max-width: 100%; }
.handoff-found .found-faces .big-card { min-width: 0; flex: 0 1 auto; }     /* (a big pile off the floor: the columns, and the cards in them, share the width) */
/* Three or more kinds (a pile off the floor): every card gets the same share of the row. */
.handoff-found .found-type:first-child:nth-last-child(n+3),
.handoff-found .found-type:first-child:nth-last-child(n+3) ~ .found-type { flex: var(--n, 1) 1 0; }
.handoff-found .found-type:nth-child(2) .found-faces .big-card:first-child { animation-delay: 0.12s; }
.found-type .ft-name { font-family: var(--serif); font-size: 20px; font-weight: 700; color: var(--brass-bright); }
.found-type .ft-desc { font-size: 14px; line-height: 1.45; color: var(--ivory); max-width: 34ch; text-align: center; text-wrap: balance; }

/* The discard screen: the discard that brings the hand down to the limit finishes it. The card is seen
   leaving for about half a second (nothing can be tapped meanwhile), then the screen closes by itself. */
#discard-overlay.leaving .card-tile { pointer-events: none; }
#discard-cards .card-tile.leaving { animation: discard-away 0.52s ease-in forwards; }
@keyframes discard-away { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-34px) scale(0.86) rotate(-5deg); } }
@keyframes discard-fade { from { opacity: 1; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { #discard-cards .card-tile.leaving { animation-name: discard-fade; } }   /* (it fades, it does not fly) */

/* End turn when it is the one thing left (no actions, but a free Espresso or Trade could still be used, so
   the turn does not end by itself): a slow, gentle glow so the button is easy to find. */
#btn-end-turn.nudge { animation: end-nudge 1.9s ease-in-out infinite; }
@keyframes end-nudge { 0%, 100% { box-shadow: 0 0 0 0 rgba(233, 201, 143, 0); } 50% { box-shadow: 0 0 0 5px rgba(233, 201, 143, 0.5); } }
@media (prefers-reduced-motion: reduce) { #btn-end-turn.nudge { animation: none; box-shadow: 0 0 0 3px rgba(233, 201, 143, 0.55); } }   /* (a steady ring) */

/* ==== Round 4, lock: choosing a key or a pick at a locked door (src/ui/lockChoice.js, index.html #lock-overlay) ====
   A small card near the padlock (JS sets left and top; the middle of the screen when it does not know where), the room
   still in view behind a light veil. One big button for each kind of card the guest holds, each with one line under it,
   and Not now. Every button is 44 px or taller. It is shorter than 340 px, so it fits the shortest iPad window (1024x694)
   between the top strip and the hand. The fan and the search icon step aside while it is up, like under any screen. */
.lock-overlay { background: rgba(8, 9, 14, 0.3); }
.lock-card {
  position: absolute; left: 0; top: 0; width: min(380px, calc(100% - 24px)); max-width: none; padding: 14px 18px 14px;
  display: flex; flex-direction: column; align-items: stretch; gap: 8px; text-align: center;
}
.lock-kicker { font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.lock-card h1.lock-title { margin: 0; font-size: 23px; line-height: 1.15; letter-spacing: 0; color: var(--brass-bright); text-wrap: balance; }
.lock-cost { margin: 0 0 2px; font-size: 14px; color: var(--ivory-dim); }
.lock-options { display: flex; flex-direction: column; gap: 8px; }
.lock-opt { display: flex; align-items: center; gap: 12px; width: 100%; min-height: 62px; padding: 8px 14px; text-align: left; }
.lock-opt-art { flex: none; width: 38px; height: 38px; color: #20170a; }
.lock-opt-art svg { width: 100%; height: 100%; display: block; }
.lock-opt-words { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.lock-opt-name { font-family: var(--serif); font-size: 18px; font-weight: 700; line-height: 1.15; color: #20170a; }
.lock-opt-hint { font-size: 13px; font-weight: 600; line-height: 1.25; color: #4a3712; text-wrap: pretty; }
.lock-warn { margin: 0; font-size: 13px; line-height: 1.35; color: var(--brass-bright); text-wrap: pretty; }
.lock-warn[hidden] { display: none; }
.lock-cancel { align-self: center; min-width: 150px; min-height: 48px; margin-top: 2px; font-family: var(--serif); font-size: 17px; font-weight: 700; }
.lock-opt:focus-visible, .lock-cancel:focus-visible { outline: 2px solid var(--brass-bright); outline-offset: 2px; }
#app:has(#lock-overlay:not([hidden])) :is(#hand-fan, .search-spot) { display: none !important; }

/* ==== Round 4, exiticon: the room action icon's second kind, the Exit icon (src/ui/searchSpot.js) ====
   The same button as the search icon (#search-spot: its place, size, tap area, caption, press and click sound), with a
   door-and-arrow on the badge. Its looks: .ready (green: this guest can leave; it pulses like the search icon), .grey
   (cannot leave yet: dimmed, still tappable) and .ap (no actions left: dimmed, as for a search; styled above). The words under
   the badge are the same for ready and grey, so the colour is the only difference. The class on the button is
   "search-spot <kind> <look>". */
.search-spot.ready .ss-badge {
  color: #0d4326;
  background: radial-gradient(circle at 38% 30%, #f4fff8 0%, #c4f2d5 45%, #8bd7ab 100%);
  border-color: #52c486;
  box-shadow: 0 0 0 2px rgba(8, 22, 14, 0.6), 0 6px 16px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(255, 255, 255, 0.6);
  animation: ss-pulse-go 1.8s ease-in-out infinite;
}
.search-spot.ready .ss-caption { color: #dcf8e6; border-color: rgba(120, 224, 164, 0.65); }
@keyframes ss-pulse-go {
  0%, 100% { transform: scale(1); box-shadow: 0 0 0 2px rgba(8, 22, 14, 0.6), 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 0 rgba(120, 224, 164, 0.6); }
  50% { transform: scale(1.08); box-shadow: 0 0 0 2px rgba(8, 22, 14, 0.6), 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 10px rgba(120, 224, 164, 0); }
}
.search-spot.grey .ss-badge { filter: grayscale(0.85) brightness(0.6); border-color: var(--brass-dim); }
.search-spot.grey .ss-caption { color: var(--ivory-dim); border-color: var(--line-soft); }
@media (prefers-reduced-motion: reduce) {
  /* (Reduce Motion: no pulse; the green badge keeps a steady ring, so "ready" is still shown) */
  .search-spot.ready .ss-badge { animation: none; box-shadow: 0 0 0 2px rgba(8, 22, 14, 0.6), 0 6px 16px rgba(0, 0, 0, 0.55), 0 0 0 4px rgba(120, 224, 164, 0.5); }
}

/* ==== Round 4, strip: a bigger guest strip, a clear "Possessed" marker, and where the round ends ====
   The top strip (src/hud.js drawStrip, src/ui/stripModel.js, src/ui/roundLabel.js roundReadout, index.html #players-strip).
   Bigger portraits, names of 14 px, hearts of 15 px on the portrait's lower edge, the turn clearly marked (a gold card and a gold tag),
   and, ONLY for a guest the viewer certainly knows is possessed, a crimson card with an eye badge and the word "Possessed" under the
   portrait (colour is never the only signal). After the last guest a dashed divider says where the round ends (a loop arrow; dawn in
   the final round), and a line under the guests loops back to the first one with "3 turns left in Round 2". The cells' width comes
   from the room the screen has between the room name (left) and the Chat / Menu buttons (right), shared among the guests. */
#hud {
  --n: 6;                                                              /* (how many guests: set by src/hud.js) */
  --strip-shift: clamp(0px, calc((1180px - 100vw) * 0.3), 30px);       /* (at 1024 wide the strip sits a little right of the middle: the room name on the left is wider than the buttons on the right) */
}
.hud-top-center { left: calc(50% + var(--strip-shift)); max-width: calc(100vw - 2 * (var(--safe-left) + 14px)); }
.players-strip {
  --pt: 72px;                                                          /* a portrait's size */
  --cw: clamp(66px, calc((100vw - 470px) / var(--n) - 4px), 96px);     /* a cell's width */
  display: flex; flex-direction: column; align-items: stretch; gap: 0; padding: 12px 8px 5px;
}
.strip-row { display: flex; justify-content: center; align-items: stretch; }
.strip-cards { display: flex; gap: 4px; align-items: flex-start; }

.mini-player {
  position: relative; flex: 0 0 var(--cw); width: var(--cw); min-width: 0; gap: 2px; padding: 12px 0 4px;
  border: 2px solid transparent; border-radius: 13px;
}
.mini-pwrap { position: relative; flex: none; width: var(--pt); height: var(--pt); }
.mini-player .mini-portrait { width: var(--pt); height: var(--pt); border-radius: 15px; border-width: 2px; }
.mini-player .mini-portrait[data-mark]::before { left: 4px; top: 4px; min-width: 23px; height: 23px; padding: 0 5px; border-radius: 12px; font-size: 14px; }
.mini-player .mini-name.u { max-width: 100%; font: 700 14px/17px var(--sans); letter-spacing: 0; }
.mini-player .mini-where { width: 100%; max-width: none; gap: 0; }
.mini-where .mini-room { font-size: 13px; line-height: 15px; }
/* Health: hearts on a dark band over the portrait's lower edge (full ones bright, empty ones dim; the last one glows). */
.mini-stats {
  position: absolute; left: 3px; right: 3px; bottom: 4px; z-index: 2; padding: 9px 0 1px; border-radius: 0 0 11px 11px; pointer-events: none;
  background: linear-gradient(rgba(8, 9, 14, 0), rgba(8, 9, 14, 0.86) 55%); text-align: center; white-space: nowrap; overflow: hidden;
  font-size: 15px; line-height: 17px; letter-spacing: 1px; color: #ff8d83;
}
.mini-stats:empty { display: none; }
.mini-stats .he { color: rgba(238, 232, 214, 0.45); }
.mini-stats.low .hf { color: #ff5a4d; text-shadow: 0 0 7px rgba(255, 90, 77, 0.7); }

/* The turn flag, sitting on the card's top edge: "Your turn" / "Playing" on a gold tag, "Next" dashed, "You" and "Out" plain. */
.mini-player .mini-flag {
  position: absolute; top: -10px; left: 50%; z-index: 4; transform: translateX(-50%);
  display: flex; align-items: center; justify-content: center; max-width: calc(100% + 4px); height: 20px; padding: 0 8px;
  border: 1px solid transparent; border-radius: 10px; font: 800 13px/1 var(--sans); letter-spacing: 0; text-transform: none; color: var(--ivory-dim);
}
.mini-player .mini-flag:not(:empty) { background: #1a1e2b; }
.mini-player.me .mini-flag, .mini-player.active.me .mini-flag { color: var(--brass-bright); }
.mini-player.next .mini-flag { color: var(--ivory); border: 1px dashed rgba(238, 232, 214, 0.6); }
.mini-player.active .mini-flag, .mini-player.active.me .mini-flag { color: #1c1406; background: var(--brass-bright); border-color: var(--brass-bright); }
.mini-player.escaped .mini-flag { color: #9fe3b8; }
.mini-player.active { border-color: var(--brass); background: linear-gradient(180deg, rgba(201, 162, 78, 0.26), rgba(201, 162, 78, 0.07)); box-shadow: 0 0 14px rgba(201, 162, 78, 0.3); }
.mini-player.next { border: 2px dashed rgba(238, 232, 214, 0.32); }
.mini-player.active .mini-portrait { border-color: var(--brass-bright); box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.45), 0 0 18px rgba(232, 202, 128, 0.6); }

/* A guest the viewer CERTAINLY knows is possessed (src/hud.js: never anyone else): a crimson card and portrait ring, the eye badge
   on the portrait's corner and the word "Possessed" under it. The turn's gold frame stays on the card when it is their turn; the
   crimson ring, the badge and the word stay on the portrait. While any guest is marked, every card has the row for the word. */
.mini-player.known { border-color: var(--crimson); background: linear-gradient(180deg, rgba(160, 38, 34, 0.46), rgba(90, 20, 24, 0.3)); box-shadow: 0 0 12px rgba(207, 74, 64, 0.28); }
.mini-player.known .mini-portrait { border-width: 3px; border-color: #e2574c; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55), 0 0 14px rgba(226, 87, 76, 0.6); }
.mini-player.active.known { border-color: var(--brass-bright); }
.mini-player.dead.known { opacity: 0.62; }
.mini-eye {
  position: absolute; top: -8px; right: -8px; z-index: 3; display: flex; align-items: center; justify-content: center;
  width: 27px; height: 27px; border-radius: 50%; background: var(--poss-red); border: 2px solid #f6ddd8; box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
}
.mini-eye svg { display: block; }
.mini-known {
  display: none; box-sizing: border-box; max-width: calc(100% + 2px); height: 20px; margin-top: 1px; padding: 0 8px; border-radius: 10px;
  background: var(--poss-red); border: 1px solid #f6ddd8; color: #fff; font: 800 13px/18px var(--sans); white-space: nowrap; visibility: hidden;
}
.players-strip.has-known .mini-known { display: block; }
.players-strip.has-known .mini-known.on { visibility: visible; }

/* Where the round ends: a dashed divider after the last guest (the loop arrow, "Round ends" written up it)... */
.strip-cap {
  flex: none; display: flex; flex-direction: column; align-items: center; gap: 4px; width: 30px; margin: 0 0 0 6px; padding: 5px 0 5px 6px;
  border-left: 2px dashed rgba(201, 162, 78, 0.7); color: var(--brass-bright);
}
.strip-cap .cap-icon { flex: none; display: block; }
.strip-cap .ic-dawn { display: none; }
.cap-word { writing-mode: vertical-rl; transform: rotate(180deg); font: 800 12px/1 var(--sans); letter-spacing: 0.05em; text-transform: uppercase; white-space: nowrap; }
/* ...and a line under the guests that loops back to the first one, with the turns left written on it. */
.strip-round { --sr: rgba(201, 162, 78, 0.7); display: flex; align-items: flex-end; gap: 8px; margin: 6px 29px 0 calc(var(--cw) / 2); }
.sr-line { position: relative; flex: 1 1 0; min-width: 10px; height: 10px; margin-bottom: 7px; border-bottom: 2px solid var(--sr); }
.sr-l { border-left: 2px solid var(--sr); border-bottom-left-radius: 8px; }
.sr-r { border-right: 2px solid var(--sr); border-bottom-right-radius: 8px; }
.sr-head { position: absolute; left: -6px; top: -7px; width: 0; height: 0; border: 5px solid transparent; border-bottom: 7px solid var(--sr); border-top: 0; }
.sr-text { flex: none; font: 700 13px/18px var(--sans); color: var(--ivory); white-space: nowrap; }
/* The last turn of the round: the divider, the line and the words turn bright, and the arrow back to the first guest nudges. */
.players-strip.last-turn .strip-round { --sr: var(--brass-bright); }
.players-strip.last-turn .sr-text { color: var(--brass-bright); }
.players-strip.last-turn .sr-head { animation: sr-nudge 1.3s ease-in-out infinite; }
@keyframes sr-nudge { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
/* The final round has no next round: dawn instead of the loop arrow, in the final round's warning colour. */
.players-strip.final .strip-cap { color: #f0b4ae; border-left-color: rgba(207, 74, 64, 0.8); }
.players-strip.final .strip-cap .ic-loop { display: none; }
.players-strip.final .strip-cap .ic-dawn { display: block; }
.players-strip.final .strip-round { --sr: rgba(224, 120, 111, 0.85); }
.players-strip.final .sr-text { color: #f6cfc9; }
@media (prefers-reduced-motion: reduce) { .players-strip.last-turn .sr-head { animation: none; } }

/* The final round's mark is on a second line of the round label ("Final round", src/hud.js), so the label is no wider than the
   Chat / Menu buttons under it and never runs under the (wider) strip beside it. */
.round-label { text-align: center; }
.round-label .round-note { display: block; margin-top: 1px; font: 800 12px/1.25 var(--sans); letter-spacing: 0.12em; text-transform: uppercase; }

/* The feed under the room name keeps clear of the (now wider) strip. */
.feed { max-width: min(340px, calc(50vw + var(--strip-shift) - (min(100px * var(--n), 100vw - 470px) + 48px) / 2 - 26px)); }   /* (up to the strip's left edge: its width is its cells plus 48 px, see --cw) */

/* Taller screens have room for bigger faces; the short ones (an iPad with Safari's bars) a smaller strip. */
@media (min-height: 900px) { .players-strip { --pt: 80px; } }
@media (max-height: 720px) {
  .players-strip { --pt: 64px; padding-bottom: 4px; }
  .mini-player { padding-top: 11px; }
  .mini-stats { font-size: 14px; line-height: 15px; letter-spacing: 0; }
  .strip-round { margin-top: 5px; }
}
/* ==== end of Round 4, strip ==== */

/* ==== Round 4, fixer ==== */
/* The Chat panel is held above the camera buttons (src/ui/chat.js place) and scrolls inside itself when the (taller) guest strip
   pushes it down: a finger drag in it scrolls the lines and never the page or the hotel behind. */
.chat-panel { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
/* ==== end of Round 4, fixer ==== */

/* ==== Round 4, discard clock ==== */
/* The discard screen's countdown (src/ui/discard.js; only where the turn clock is on): the seconds large and calm with a bar
   running down beside them; the last 5 seconds turn crimson, and the number pulses gently (Reduce Motion: it only turns
   crimson). The bar is a picture: the words are the text, and #discard-live (hidden, polite) says "10 seconds left" and "5 seconds left". */
.discard-clock { display: flex; align-items: center; gap: 16px; margin: 2px 4px 10px; }
.discard-clock[hidden] { display: none; }
.dc-words { flex: none; display: flex; align-items: baseline; gap: 8px; font-family: var(--serif); white-space: nowrap; }
.dc-secs { min-width: 2ch; text-align: right; font-size: 36px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; color: var(--brass-bright); }
.dc-label { font-size: 15px; color: var(--ivory-dim); }
.dc-track { flex: 1 1 auto; height: 8px; border-radius: 999px; background: rgba(0, 0, 0, 0.45); overflow: hidden; }
.dc-fill { width: 100%; height: 100%; background: linear-gradient(90deg, var(--brass), var(--brass-bright)); transform-origin: left center; }   /* (shrunk by discard.js: transform: scaleX) */
.discard-clock.urgent .dc-secs { color: #f0b4ae; animation: dc-pulse 1.1s ease-in-out infinite; }
.discard-clock.urgent .dc-fill { background: linear-gradient(90deg, #8c3a34, var(--crimson)); }
@keyframes dc-pulse { 50% { opacity: 0.6; } }
@media (prefers-reduced-motion: reduce) { .discard-clock.urgent .dc-secs { animation: none; } }
#discard-sub { text-wrap: balance; }      /* (no lonely last word on the third line once the clock's sentence is added) */
.discard-live { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* "Time ran out. The game discarded your ..." : a calm card over the game for a few seconds, on the player's own screen only.
   It blocks nothing (taps go through it) and sits above the toast line. */
.discard-note {
  position: absolute; left: 50%; bottom: calc(var(--safe-bottom) + 262px); transform: translateX(-50%); z-index: 11;
  width: max-content; max-width: min(520px, 90vw); padding: 12px 20px; border-radius: 14px; text-align: center; pointer-events: none;
  font-family: var(--serif); font-size: 17px; line-height: 1.4; color: var(--ivory); text-wrap: balance;
  background: var(--panel); border: 1px solid var(--line);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.5), 0 8px 20px rgba(0, 0, 0, 0.5);
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
}
.discard-note[hidden] { display: none; }
/* ==== end of Round 4, discard clock ==== */

/* ==== Round 4, rooms: the Infirmary's and the Switchboard's icons (src/ui/searchSpot.js, kinds heal and switchboard) ====
   The same button as the search icon (its place, size, tap area, caption, press and click sound). The cross is crimson and the
   headset a deep blue on the brass badge (the colours of their marks on the Map). Looks: .live pulses like the search icon (the
   rule above); .full (an Infirmary, and the guest is at full health: nothing is spent) and .spent (somebody has used this
   Infirmary: it works once per match, for everyone) are dimmed and still tappable, .spent with a small green tick; .ap (too few
   actions) is dimmed by the search icon's rule. A second icon, #search-spot-2, is the magnifier beside the room's own action
   when a dead guest's cards lie in the room: it is the same button as the first, in its own clear place. */
.search-spot.heal .ss-badge { color: #b3302a; }
.search-spot.switchboard .ss-badge { color: #1f4a72; }
.search-spot.full .ss-badge, .search-spot.spent .ss-badge { filter: grayscale(0.85) brightness(0.6); border-color: var(--brass-dim); }
.search-spot.full .ss-caption, .search-spot.spent .ss-caption { color: var(--ivory-dim); border-color: var(--line-soft); }
.search-spot .ss-tick {
  display: none; position: absolute; left: calc(50% + 7px); top: 36px; width: 26px; height: 26px; border-radius: 50%;
  align-items: center; justify-content: center; pointer-events: none;
  background: #8bd7ab; border: 2px solid #1f6b45; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
}
.search-spot .ss-tick svg { width: 15px; height: 15px; }
.search-spot.spent .ss-tick { display: flex; }
/* ==== end of Round 4, rooms ==== */
