/* ==========================================================================
   THE DECEIVERS — Design System
   Dark ceremonial aesthetic. Tokens -> base -> layout -> components -> screens -> motion.
   ========================================================================== */

:root {
  /* Rendering correction, fourth pass: pulp-comic / Dick Tracy printing,
     not "premium dark app". Hard rule set, not a guess —
     JET BLACK + CREAM + SATURATED YELLOW + BLOOD RED, almost no
     mid-grey, no translucent panels washing black toward charcoal.
     Keeping the existing --charcoal-* / --gold-* / --crimson-* / --ink names
     (every component already consumes them) but setting their VALUES to
     the hard rule — not renaming to --ink/--panel/etc as literally
     proposed, since --ink already means "text colour" throughout this
     file and reusing it for "page black" would silently invert every
     text rule. --charcoal-950 IS the page-black requirement (#000000);
     --charcoal-900/800 are the panel blacks; --gold-500 and
     --crimson-500 are the exact hard yellow/red; --ink/--ink-dim are the
     exact cream/muted text colours. */
  --charcoal-950: #000000;
  --charcoal-900: #05090c;
  --charcoal-800: #06111b;
  --charcoal-700: #0b1824;

  --gold-300: #fbd873;
  --gold-400: #f8c730;
  --gold-500: #f5be16;
  --gold-700: #c98e0a;
  --gold-900: #000000;

  --crimson-900: #2b0407;
  --crimson-700: #8c0b10;
  --crimson-500: #c81920;

  --midnight-900: #141c30;
  --midnight-700: #1f2a44;
  --midnight-500: #3a4a72;

  --parchment-100: #e9dcc0;
  --parchment-300: #d8c9a3;
  --parchment-muted: #a9895a;

  --ink: #f3e7c5;
  --ink-dim: #a79f91;

  /* Component language, third pass: the painted-poster house style reads
     as cinematic/ceremonial through hard-edged, slightly chamfered cards
     and controls, not soft rounded pills — pills now read as "generic
     mobile web app" next to that artwork. --radius-pill survives only
     for genuinely circular things (avatar discs, icon-only taps);
     everything else (buttons, fields, panels, rows) clips to a shallow
     cut-corner hexagon via --clip-chamfer/-sm instead of border-radius,
     which also makes the border itself follow the cut corners for free
     (clip-path clips border-box by default). --hairline is the default,
     low-contrast edge for ordinary containers; a visible --gold-700/500
     border is reserved for components that are themselves a significant
     choice or state (primary CTA, selected toggle, the prize pot, a
     modal) — see the design review that prompted this pass: almost
     everything had the same gold ring, so nothing did. --field-bg is
     deliberately darker/less saturated than --charcoal-800 (which still
     reads fine as a large panel fill) — at form-field size the same
     navy read as "bright blue input box", not "dark ceremonial ledger". */
  --radius-lg: 18px 22px 19px 23px;
  --radius-md: 12px 16px 13px 15px;
  --radius-sm: 7px 11px 8px 10px;
  --radius-pill: 999px;
  --radius-tight: 4px;
  --clip-chamfer: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  --clip-chamfer-sm: polygon(5px 0, 100% 0, 100% calc(100% - 5px), calc(100% - 5px) 100%, 0 100%, 0 5px);
  --hairline: rgba(243,231,197,0.1);
  --field-bg: #000000;

  --shadow-deep: 0 18px 40px rgba(0,0,0,0.55);
  --shadow-soft: 0 8px 20px rgba(0,0,0,0.4);

  --dur-fast: 140ms;
  --dur-med: 320ms;
  --dur-slow: 620ms;

  --font-display: 'Anton', 'Arial Narrow', 'Helvetica Neue', sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* Mobile browser chrome (address bars, bottom toolbars, in-app-browser
     nav bars on shared links) routinely overlaps the outer edges of the
     viewport in ways env(safe-area-inset-*) alone doesn't cover — that's
     really only for notches/home-indicators. A flat 10% reservation at
     each edge is the blunt, reliable fix; env() is layered in on top for
     notch devices where that's larger than 10vh. */
  --edge-buffer-top: max(10vh, env(safe-area-inset-top, 0px));
  --edge-buffer-bottom: max(10vh, env(safe-area-inset-bottom, 0px));

  color-scheme: dark;
}

/* ---------- Reset / base ---------- */
* { box-sizing: border-box; }
html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--charcoal-950);
}
body {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  font-family: var(--font-body);
  color: var(--ink);
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
}
button {
  font-family: inherit;
  cursor: pointer;
}
h1, h2, h3, p { margin: 0; }
ul { list-style: none; margin: 0; padding: 0; }
input {
  font-family: inherit;
}
.hidden { display: none !important; }
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Background texture: subtle vignette + faint radial noise, CSS only */
body {
  background:
    radial-gradient(ellipse at 50% -10%, rgba(245,190,22,0.08), transparent 55%),
    radial-gradient(ellipse at 50% 110%, rgba(200,25,32,0.10), transparent 60%),
    var(--charcoal-950);
}

/* ---------- App shell ---------- */
.app {
  position: relative;
  width: 100vw;
  max-width: 430px;
  height: 100svh;
  min-height: 100vh;
  background: linear-gradient(180deg, var(--charcoal-900), var(--charcoal-950) 60%);
  box-shadow: var(--shadow-deep);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Mancave Industries / Game Shed badge, worked in as an always-there
   watermark at the brand's specified 15% opacity — screen blend mode
   drops its own dark background out against ours and brightens the
   cream/gold linework, so it reads as a legible stamp rather than a flat
   logo pasted on top. Sits behind every screen (.screen has no background
   of its own, so this shows through the empty space of all of them) and
   never intercepts taps. */
/* A physical stamp pressed into the corner of the composition, not a
   logo centred neatly behind the content -- oversized and cropped off
   two edges by .app's own overflow:hidden, no vignette mask holding it
   to a tidy circle. */
/* A true alpha-transparent ink stamp (not a flattened JPEG with a solid
   maroon background pretending to be transparent via blend-mode tricks
   -- that's what was reading as "a maroon rectangle laid over the
   page"). mancave-gameshed-stamp.png is built from the badge art with
   its own background keyed out to real alpha, linework recolored to a
   single cream ink tone, so plain opacity is all it needs now -- no
   blend-mode, no background fill of any kind. */
.app::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url('../assets/brand/mancave-gameshed-stamp.png');
  background-repeat: no-repeat;
  background-position: 145% 85%;
  background-size: 120%;
  opacity: 0.09;
}

/* A hairline ceremonial frame, inset from the device edge, with four
   corner brackets instead of a full rectangle — reads as "designed card",
   not "blank page", on every screen at once with zero per-screen work. */
.app::after {
  content: "";
  position: absolute;
  inset: 10px;
  z-index: 1;
  pointer-events: none;
  border: 1px solid rgba(245,190,22,0.08);
  background:
    linear-gradient(var(--gold-500), var(--gold-500)) top left / 24px 3px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) top left / 3px 24px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) top right / 24px 3px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) top right / 3px 24px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) bottom left / 24px 3px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) bottom left / 3px 24px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) bottom right / 24px 3px no-repeat,
    linear-gradient(var(--gold-500), var(--gold-500)) bottom right / 3px 24px no-repeat;
  opacity: 0.55;
  filter: url(#crumble);
}

/* Atmospheric layer, cropped straight from the approved house-style
   artwork (moon + castle skyline) rather than invented fresh — anchors
   the top of every screen. It is SCENERY, not a translucent wash over
   the UI: rendered near-full opacity so the art stays saturated, with
   no separate scrim/gradient layered over it or over the controls below
   it. The darken-for-readability work is baked directly into the
   image's own alpha channel (night-skyline.png fades itself out by
   ~70-95% of its own height) so it falls into the app's own true-black
   background on its own, abruptly rather than through a long grey
   gradient smear. Text sitting over the art band gets its contrast from
   a tight drop-shadow on the type itself (see .screen-title-row etc.),
   never from dimming this layer or anything beneath it. */
/* The previous version relied on the PNG's own baked-in alpha fade to
   dissolve into black -- but background-size:cover on a wide/short box
   (~390x240) against a tall portrait source (377x868) scales to fit
   width and crops from the top down, so the box's bottom edge lands
   well inside the image's fully-opaque region; the fade baked into the
   file never gets a chance to render, leaving a hard rectangular cut
   (exactly "a banner sitting above the UI"). Fixed properly this time
   with a CSS mask on the layer itself, which fades regardless of how
   the image is cropped: a single radial ellipse, opaque near top-
   center, dissolving toward both the bottom AND the left/right edges
   at once, so the scene reads as atmosphere emerging from black rather
   than a photo dropped into a header. */
/* Restrained motif, not a hero image: short enough and fading fast
   enough that it resolves to true black before the screen title even
   starts, let alone the body copy beneath it -- "establish atmosphere,
   then get out of the way," not a moon sitting behind ordinary text. */
.app-skyline {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--edge-buffer-top)) 0 auto 0;
  height: 24vh;
  z-index: 0;
  pointer-events: none;
  opacity: 0.9;
  background: url('../assets/brand/night-skyline.png') center top / cover no-repeat;
  -webkit-mask-image: linear-gradient(to bottom,
    #000 0%,
    #000 40%,
    rgba(0,0,0,0.6) 60%,
    transparent 85%);
  mask-image: linear-gradient(to bottom,
    #000 0%,
    #000 40%,
    rgba(0,0,0,0.6) 60%,
    transparent 85%);
}

/* A faint, always-on film-grain pass over the whole app. Multiply blend
   only ever darkens -- true black stays true black -- unlike overlay/
   soft-light, which lift lighter pixels and were the main cause of the
   washed-out "grey veil" look this theme had to be corrected away from. */
.app-grain {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url('../assets/brand/grain.png');
  background-repeat: repeat;
  background-size: 64px 64px;
  mix-blend-mode: multiply;
  opacity: 0.07;
}

.sprite-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.icon {
  width: 22px;
  height: 22px;
  display: inline-block;
  color: var(--gold-400);
  fill: none;
  flex-shrink: 0;
  object-fit: contain; /* no-op for the inline-SVG icons, keeps the raster icon family (see iconUse in ui.js) from ever distorting */
}
.icon-lg { width: 32px; height: 32px; }
.icon-sm { width: 16px; height: 16px; }

/* ---------- Header ---------- */
.app-header {
  position: relative;
  flex: 0 0 auto;
  height: calc(52px + var(--edge-buffer-top));
  display: grid;
  grid-template-columns: 44px 1fr 44px 44px;
  align-items: end;
  padding: var(--edge-buffer-top) 6px 8px;
  border-bottom: 1px solid rgba(245,190,22,0.3);
  background: transparent;
  z-index: 20;
}
/* Fills the --edge-buffer-top safe-area reservation above the icon row --
   previously just blank space on every screen except Title (which has
   its own full poster). Sized to the buffer itself (height: 100%, since
   the header's own top padding IS that buffer), so it never competes
   with the icon row for space; pointer-events: none keeps it purely
   decorative, since the tappable icons already sit in their own area
   below this one. Same grainy-gold text treatment as .screen-title-row
   and friends, just reused here rather than a new image asset. Width
   constrained with min(vh, vw) so it scales down safely on both a short
   landscape-ish viewport and a narrow one, not just one axis. */
.app-header-wordmark {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--edge-buffer-top);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(20px, min(9vh, 8vw), 44px);
  letter-spacing: 1.5px;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--gold-500);
  text-shadow: 2px 2px 0 rgba(0,0,0,0.9);
}
.icon-btn {
  width: 40px;
  height: 40px;
  border: none;
  background: transparent;
  border-radius: var(--radius-pill);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--dur-fast) ease;
}
.icon-btn:active { background: rgba(245,190,22,0.15); }
.header-mid {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1.1;
  overflow: hidden;
}
/* Flat, saturated gold display text -- pulp-ink printing, not a metallic
   gradient. A gradient (even gold-to-gold) plus a soft-light-blended
   grain clipped to the glyphs is exactly what read as "antique/brassy"
   instead of punchy ink-yellow; a hard offset shadow (zero blur) gives
   it weight/contrast against the art without turning into a soft glow. */
.screen-title-row,
.reveal-headline,
.winner-banner h2,
.modal-title,
.prize-pot-value {
  color: var(--gold-500);
  text-shadow: 2px 2px 0 rgba(0,0,0,0.9);
}

.round-label {
  font-family: var(--font-display);
  font-size: 15px;
  letter-spacing: 1.5px;
  color: var(--gold-300);
  text-shadow: 1px 1px 0 rgba(0,0,0,0.9);
}
.phase-label {
  font-family: var(--font-display);
  font-size: 12.5px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-shadow: 1px 1px 0 rgba(0,0,0,0.9);
}

/* ---------- Screens ---------- */
.screens {
  position: relative;
  flex: 1 1 auto;
  overflow: hidden;
}
.screen {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  padding: 16px 18px calc(18px + var(--edge-buffer-bottom));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.screen.active {
  display: flex;
  animation: screenFade var(--dur-med) ease;
}
@keyframes screenFade {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.screen-title-row {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(26px, 7.5vw, 31px);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--gold-500);
  text-align: center;
  margin-bottom: 4px;
  text-shadow: 2px 2px 0 rgba(0,0,0,0.9);
}
.screen-subtitle {
  font-size: 14px;
  color: var(--ink-dim);
  text-align: center;
  margin-bottom: 10px;
  line-height: 1.4;
  text-shadow: 1px 1px 0 rgba(0,0,0,0.9);
}

/* ---------- Buttons ---------- */
.btn {
  position: relative;
  appearance: none;
  font-family: var(--font-display);
  border: 2.5px solid var(--hairline);
  border-radius: 0;
  clip-path: var(--clip-chamfer);
  padding: 14px 22px;
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  text-align: center;
  transition: transform var(--dur-fast) ease;
}
.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.4; pointer-events: none; }
.btn-block { display: block; width: 100%; }
.btn-sm { padding: 9px 16px; font-size: 14px; letter-spacing: 0.6px; }

/* Painted-poster richness, not flat ink: a soft top-to-bottom gradient
   and a faint glow, matching the approved key art's own glossy card/
   crown rendering, rather than a flat screen-printed block. Texture
   stays a separate low-opacity multiply pass so it can only darken --
   the gradient underneath still can't wash out toward grey/brass. */
.btn::after,
.prize-pot-panel::after,
.winner-banner::after,
.modal-panel::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url('../assets/brand/grain.png');
  background-repeat: repeat;
  background-size: 40px 40px;
  mix-blend-mode: multiply;
  opacity: 0.08;
  pointer-events: none;
}
.btn-primary, .btn-confirm {
  color: var(--charcoal-950);
  background: var(--gold-500);
  border-color: #000000;
}
.btn-danger {
  color: var(--ink);
  background: var(--crimson-500);
  border-color: #000000;
}
.btn-ghost {
  color: var(--ink);
  background: var(--field-bg);
  border-color: rgba(245,190,22,0.4);
}

/* ---------- Generic panel ---------- */
/* Poster hierarchy, not settings-screen hierarchy: a section is a
   heading plus one thin gold rule, not a bordered box on a background
   fill. Open black space does the separating instead of a frame. */
.panel {
  padding: 0;
}
.panel-title {
  font-family: var(--font-display);
  font-size: 16px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--gold-500);
  padding-bottom: 7px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--gold-700);
}

/* ---------- Title screen ---------- */
/* The title key art is tall/portrait (built for a phone screen), so it
   runs full-bleed as #screen-title's own background rather than sitting
   in a small framed box — background-origin/-clip default to padding-box/
   border-box, so it already shows straight through .screen's own padding
   with no extra markup. The lockup (title, tagline, brand) lives in the
   image's upper two-thirds; the buttons sit in its emptier lower third. */
#screen-title {
  background-image: url('../assets/brand/deceivers-title-poster.jpg?v=202610071539');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.title-hero {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  padding-bottom: 28px;
  text-align: center;
}
.title-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: 280px;
}

/* ---------- Setup screen ---------- */
.setup-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.setup-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--field-bg);
  border: 1px solid rgba(245,190,22,0.65);
  border-radius: 0;
  clip-path: var(--clip-chamfer-sm);
  padding: 6px 10px;
  transition: border-color var(--dur-fast) ease;
}
.setup-row:focus-within { border-color: var(--gold-500); }
.setup-row .seat-index {
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 0.5px;
  color: var(--gold-500);
  width: 22px;
  text-align: center;
  flex-shrink: 0;
}
.name-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  color: var(--ink);
  font-size: 17px;
  padding: 8px 4px;
  outline: none;
}
.name-input::placeholder { color: var(--ink-dim); }
.setup-player-block { display: flex; flex-direction: column; gap: 6px; }
.seat-mode-row { display: flex; gap: 10px; padding-left: 30px; }
/* A plain 2-way selector, not a pair of boxes inside a box: unselected is
   just dim text with no border/fill at all; only the chosen state carries
   weight (solid yellow fill, black text). No outer frame around the pair. */
.seat-mode-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 7px 8px;
  border: none;
  border-radius: 0;
  background: transparent;
  color: var(--ink-dim);
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}
.seat-mode-btn.active {
  color: var(--charcoal-950);
  background: var(--gold-500);
  font-weight: 700;
}
.remove-player-btn {
  background: none;
  border: none;
  color: var(--crimson-500);
  font-size: 20.5px;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
}
.add-player-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 10px;
  border: none;
  background: transparent;
  color: var(--gold-500);
  font-family: var(--font-display);
  font-size: 14.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.setup-hint {
  font-size: 12.5px;
  letter-spacing: 0.3px;
  color: var(--ink-dim);
  text-align: center;
  margin-bottom: 6px;
}
.stepper-btn {
  appearance: none;
  width: 38px;
  height: 38px;
  border: 1px solid var(--hairline);
  border-radius: 0;
  clip-path: var(--clip-chamfer-sm);
  background: var(--field-bg);
  color: var(--gold-400);
  font-size: 20px;
  line-height: 1;
  flex-shrink: 0;
}
.stepper-btn:active { background: var(--charcoal-800); }

/* ---------- Player list (main screen) ---------- */
/* The circle is ONE ledger, not a stack of separate cards: a single rule
   above the list, a hairline between rows, and the gold/crimson left
   edge carries status -- no per-row box, no background fill. */
.player-list { display: flex; flex-direction: column; border-top: 1px solid var(--hairline); }
.player-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 4px 12px 12px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--hairline);
  border-left: 3px solid var(--gold-500);
  position: relative;
}
.player-row.eliminated {
  opacity: 0.5;
  border-left-color: var(--crimson-700);
  filter: grayscale(0.6);
}
.player-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--charcoal-700);
  border: 1.5px solid var(--gold-500);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 17px;
  color: var(--gold-300);
  flex-shrink: 0;
}
.player-name { flex: 1; font-family: var(--font-display); font-size: 19px; letter-spacing: 0.3px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.player-meta { font-size: 12px; color: var(--ink-dim); }
.player-badge { width: 18px; height: 18px; color: var(--crimson-500); flex-shrink: 0; }

/* ---------- Prize pot panel ---------- */
.prize-pot-panel {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  position: relative;
  background: var(--charcoal-900);
  border: 2px solid var(--gold-500);
  border-radius: 0;
  clip-path: var(--clip-chamfer);
  padding: 14px;
  margin-bottom: 14px;
}
.prize-pot-value {
  font-family: var(--font-display);
  font-size: 34.5px;
  color: var(--gold-300);
  line-height: 1;
}
.prize-pot-label {
  font-size: 11.5px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* ---------- Cards ---------- */
.card {
  position: relative;
  width: 128px;
  aspect-ratio: 200 / 280;
  border-radius: var(--radius-md);
  flex-shrink: 0;
  perspective: 1000px;
}
.card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform var(--dur-slow) cubic-bezier(.4,.1,.2,1);
}
.card.flipped .card-inner { transform: rotateY(180deg); }
.card-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}
.card-face svg { width: 100%; height: 100%; display: block; }
.card-face.card-back-face { }
.card-face.card-front-face { transform: rotateY(180deg); }
.card-lg { width: 168px; }
.card-xl { width: 200px; }

/* ---------- Hand tray ---------- */
.hand-tray {
  position: relative;
  margin: 0 -18px -18px;
  padding: 16px 18px 20px;
  background: linear-gradient(180deg, var(--charcoal-800), var(--charcoal-950));
  border-top: 2px solid var(--gold-500);
  border-radius: 20px 20px 0 0;
}
.hand-tray-label {
  font-size: 11.5px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: 8px;
  text-align: center;
}
.hand-scroll {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.hand-scroll .card { width: 92px; }
.hand-empty {
  text-align: center;
  color: var(--ink-dim);
  font-size: 14.5px;
  padding: 10px 0;
}
.hand-card-wrap { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.hand-card-wrap .card.selectable { cursor: pointer; }
.hand-card-wrap .card.selected .card-inner { outline: 2px solid var(--gold-400); outline-offset: 3px; border-radius: var(--radius-md); }
.hand-card-name { font-size: 11.5px; color: var(--ink-dim); text-align: center; max-width: 92px; }
.hand-card-desc { font-size: 11px; color: var(--ink-dim); opacity: 0.85; text-align: center; max-width: 100px; line-height: 1.35; display: block; }

/* ---------- Grids (murder / vote target selection) ---------- */
.target-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.target-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 8px;
  border-radius: 0;
  clip-path: var(--clip-chamfer);
  background: var(--charcoal-900);
  border: 1px solid var(--hairline);
  color: var(--ink);
  font-size: 15px;
  text-align: center;
}
.target-card:active { transform: scale(0.97); }
.target-card.selected {
  border-color: var(--gold-400);
  background: linear-gradient(160deg, var(--gold-900), var(--charcoal-800));
  box-shadow: 0 0 0 2px var(--gold-400) inset;
}
.target-card .player-avatar { width: 44px; height: 44px; font-size: 20.5px; }

/* ---------- Privacy badge (PRIVATE / PUBLIC labeling, issue #2) ---------- */
/* Icon + text together, never colour alone -- WCAG 1.4.1. Chamfered like
   every other component here (buttons, toggles, panels), not a pill --
   see the component-language note at the top of this file. */
.privacy-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px 7px 11px;
  clip-path: var(--clip-chamfer-sm);
  border: 2px solid #000000;
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  align-self: center;
  margin-bottom: 14px;
}
/* .reveal-stage already spaces its children with its own gap -- cancel
   the badge's own margin there so the two don't stack. */
.reveal-stage > .privacy-badge { margin-bottom: 0; }
.privacy-badge .icon { width: 17px; height: 17px; flex-shrink: 0; }
.privacy-badge.is-private { background: var(--crimson-500); color: var(--ink); }
.privacy-badge.is-public { background: var(--gold-500); color: var(--charcoal-950); }

/* ---------- Pass-device overlay ---------- */
.pass-overlay {
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  text-align: center;
  padding: 30px;
  background: var(--charcoal-950);
}
.pass-overlay .icon-lg { width: 54px; height: 54px; }
.pass-overlay-eyebrow {
  font-family: var(--font-display);
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.pass-overlay-name {
  font-family: var(--font-display);
  font-size: 32px;
  color: var(--gold-300);
}
.pass-overlay-instruction {
  font-size: 15.5px;
  color: var(--ink-dim);
  max-width: 260px;
  line-height: 1.5;
}

/* ---------- Elimination / ceremonial reveal ---------- */
/* Shared by every pass-the-phone prompt, role/card reveal, and outcome
   screen — by far the most-seen layout in the game — so bracketing it
   top and bottom with the same dot-and-line rule used elsewhere turns
   each one into a framed ceremony beat instead of a few lines floating
   in a mostly-empty screen. */
.reveal-stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  text-align: center;
}
/* Radiating gold sunburst behind the stage's main ceremonial icon
   (skull, compass, candle, etc.) -- matches the house-style mockup's
   engraved-halo treatment on Murder/Gather Everyone/etc. without any new
   art: a conic gradient standing in for the rays, with a soft radial
   glow underneath so it reads as light, not a sharp starburst graphic. */
.reveal-stage > .icon-lg {
  position: relative;
}
.reveal-stage > .icon-lg::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 150px;
  height: 150px;
  transform: translate(-50%, -50%);
  z-index: -1;
  background:
    repeating-conic-gradient(from 0deg, var(--gold-500) 0deg 2deg, transparent 2deg 15deg),
    radial-gradient(circle, rgba(245,190,22,0.22), transparent 62%);
  -webkit-mask-image: radial-gradient(circle, #000 38%, transparent 68%);
  mask-image: radial-gradient(circle, #000 38%, transparent 68%);
  opacity: 0.55;
}
.reveal-stage::before, .reveal-stage::after {
  content: "";
  width: 130px;
  height: 10px;
  flex-shrink: 0;
  background:
    radial-gradient(circle, var(--gold-500) 0 1.5px, transparent 2.5px) center / 10px 10px no-repeat,
    linear-gradient(90deg, transparent, var(--gold-700) 32%, var(--gold-700) 68%, transparent) center / 100% 1px no-repeat;
  opacity: 0.35;
}
.reveal-headline {
  font-family: var(--font-display);
  font-size: 25.5px;
  text-transform: uppercase;
  color: var(--gold-300);
  letter-spacing: 1px;
}
.reveal-body { font-size: 15.5px; color: var(--ink-dim); max-width: 280px; line-height: 1.5; }

/* ---------- Results screen ---------- */
.winner-banner {
  position: relative;
  text-align: center;
  padding: 18px;
  margin-bottom: 16px;
  border-radius: 0;
  clip-path: var(--clip-chamfer);
  border: 2px solid var(--gold-400);
  background: var(--charcoal-900);
}
.winner-banner h2 {
  font-family: var(--font-display);
  font-size: 27.5px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--gold-300);
}
.role-reveal-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.role-reveal-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 0;
  clip-path: var(--clip-chamfer-sm);
  background: var(--charcoal-900);
  border: 1px solid var(--hairline);
}
.role-reveal-row.deceiver { border-left: 4px solid var(--crimson-500); }
.role-reveal-row.loyal { border-left: 4px solid var(--midnight-500); }

/* ---------- Modal ---------- */
/* ---------- Interstitials ----------
   Brief fullscreen transition cards between major phases (Draw, Night,
   Murder, Banishment, Reveal, Final Circle, etc.) — see ui.js's
   showInterstitial and the INTERSTITIAL_IMAGES map. z-index above the
   modal (80 vs 60): the two should never overlap in practice, but if a
   modal were somehow left open, the interstitial still needs to read as
   the more urgent, momentary thing. Tap anywhere to skip early. */
.interstitial-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--charcoal-950);
  cursor: pointer;
  animation: interstitialFade 220ms ease;
}
.interstitial-overlay.hidden { display: none; }
.interstitial-overlay img,
.interstitial-overlay video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
@keyframes interstitialFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: max(20px, var(--edge-buffer-top)) 20px max(20px, var(--edge-buffer-bottom));
  background: rgba(0,0,0,0.9);
}
.modal-panel {
  width: 100%;
  max-width: 340px;
  max-height: 80vh;
  overflow-y: auto;
  background: var(--charcoal-900);
  border: 2px solid var(--gold-500);
  border-radius: 0;
  clip-path: var(--clip-chamfer);
  padding: 22px 20px;
  position: relative;
}
.modal-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--gold-400);
  font-size: 25.5px;
  line-height: 1;
}
.modal-title {
  font-family: var(--font-display);
  font-size: 20.5px;
  text-transform: uppercase;
  color: var(--gold-400);
  letter-spacing: 1px;
  margin-bottom: 12px;
  text-align: center;
}
.modal-body { font-size: 15.5px; color: var(--ink-dim); line-height: 1.6; }
.modal-body p { margin-bottom: 10px; }
.modal-body .rule-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }

/* ---------- Toast ---------- */
.toast {
  position: absolute;
  left: 50%;
  bottom: 90px;
  transform: translateX(-50%);
  z-index: 55;
  background: var(--charcoal-950);
  border: 1.5px solid var(--gold-500);
  color: var(--gold-300);
  font-size: 15px;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  animation: toastPop 2.2s ease forwards;
  white-space: nowrap;
}
@keyframes toastPop {
  0% { opacity: 0; transform: translateX(-50%) translateY(8px); }
  12% { opacity: 1; transform: translateX(-50%) translateY(0); }
  82% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(-6px); }
}

/* ---------- Candle flicker (used on quiet-night / night screens) ---------- */
.flicker { animation: flicker 2.6s ease-in-out infinite; }
@keyframes flicker {
  0%, 100% { opacity: 1; }
  45% { opacity: 0.82; }
  55% { opacity: 1; }
  70% { opacity: 0.88; }
}

.fade-in { animation: fadeIn var(--dur-med) ease; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.scale-in { animation: scaleIn var(--dur-med) cubic-bezier(.3,.2,.2,1.3); }
@keyframes scaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }

/* ---------- Misc ---------- */
/* Every screen with a short, variable-length body (few players, an empty
   hand, a short player list) ends with a .spacer pushing the primary
   button to the bottom — on a tall phone that used to be bare dead air.
   A single faint ceremonial rule — line, dot, line — fills it without
   adding fake content or touching ui.js's six call sites. */
.spacer {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 12px;
}
.spacer::before {
  content: "";
  display: block;
  width: 130px;
  height: 10px;
  background:
    radial-gradient(circle, var(--gold-500) 0 1.5px, transparent 2.5px) center / 10px 10px no-repeat,
    linear-gradient(90deg, transparent, var(--gold-700) 32%, var(--gold-700) 68%, transparent) center / 100% 1px no-repeat;
  opacity: 0.4;
}
.stack { display: flex; flex-direction: column; gap: 10px; }
.center-text { text-align: center; }
.small-note { font-size: 12.5px; color: var(--ink-dim); text-align: center; }

@media (min-width: 431px) {
  html, body { background: var(--charcoal-950); }
}
