/* ─── Offline fonts (@font-face) ────────────────────────── */
/* Fonts are self-hosted in public/fonts/ so the app works with no internet. */
@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/BarlowCondensed-Regular.ttf') format('truetype');
}

@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/BarlowCondensed-Bold.ttf') format('truetype');
}

@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('/fonts/BarlowCondensed-Black.ttf') format('truetype');
}

@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/Barlow-Regular.ttf') format('truetype');
}

@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/Barlow-SemiBold.ttf') format('truetype');
}

@font-face {
  font-family: 'Barlow';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/Barlow-Bold.ttf') format('truetype');
}

:root {
  /* Brand colours */
  --color-primary:        #9e1817;   /* Brand red */
  --color-primary-hover:  #6b0f10;   /* primary darkened for hover states */
  --color-secondary:      #000000;   /* Black */
  --color-accent:         #9e1817;   /* Brand red */
  --color-success:        #9e1817;
  --color-success-hover:  #6b0f10;
  --color-danger:         #9e1817;
  --color-danger-hover:   #6b0f10;
  --color-neutral:        #FFFFFF;

  /* Text */
  --color-text-primary:   #000000;
  --color-text-secondary: rgba(0, 0, 0, 0.7);
  --color-text-dark:      #000000;
  --color-text-on-primary: #FFFFFF;

  /* Surfaces */
  --color-background:     #FFFFFF;
  --color-surface:        #FFFFFF;
  --color-surface-raised: #f5f5f5;
  --color-border:         rgba(0, 0, 0, 0.15);

  /* Typography
   * Barlow Condensed: high-impact display text — wide characters are legible
   * from the back of a 200-seat room at large sizes.
   * Barlow: body text — same family, slightly wider, keeps scan easy at distance.
   * Both self-hosted in public/fonts/ — no CDN required at event time.
   *
   * MINIMUM FONT SIZE RULE: --font-size-sm (1.5rem / 24px) is the floor.
   * No in-game element — question text, answer options, values, banker offers —
   * may use a smaller font-size. UI chrome (presenter bar, overlays) may drop to
   * 1rem only if it is never projected as primary content.
   */
  --font-display:  'Barlow Condensed', sans-serif;
  --font-body:     'Barlow', sans-serif;
  --font-size-xl:  clamp(3rem, 6vw, 5rem);     /* question text */
  --font-size-lg:  clamp(2rem, 4vw, 3.5rem);   /* answer options / values */
  --font-size-md:  clamp(1.5rem, 2.5vw, 2rem); /* labels, banker offer text */
  --font-size-sm:  1.5rem;                      /* minimum — nothing smaller in-game */

  /* Spacing */
  --spacing-xs:    0.5rem;
  --spacing-sm:    1rem;
  --spacing-md:    2rem;
  --spacing-lg:    4rem;

  /* Animation */
  --transition-fast:   150ms ease;
  --transition-normal: 300ms ease;
  --transition-slow:   600ms ease;

  /* Borders */
  --radius-sm:  8px;
  --radius-md:  16px;
  --radius-lg:  32px;
}

/* ─── Reset ─────────────────────────────────────────────── */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
  overflow: hidden;
  font-family: var(--font-body);
  background-color: var(--color-background);
  color: var(--color-text-primary);
  font-size: 16px;
  line-height: 1.4;
}

body {
  display: flex;
  flex-direction: column;
}

button {
  font-family: inherit;
  cursor: pointer;
}

/* ─── Presenter Bar ─────────────────────────────────────── */
#presenter-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-xs) var(--spacing-md);
  background-color: #FFFFFF;
  border-bottom: 2px solid #9e1817;
  position: sticky;
  top: 0;
  z-index: 100;
  height: 3.5rem;
  gap: var(--spacing-sm);
  animation: gs-slide-in-down 500ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.presenter-bar__left,
.presenter-bar__right {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}

.presenter-bar__logo {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--color-primary);
  white-space: nowrap;
}

.presenter-bar__rounds {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}

.presenter-bar__label {
  font-size: 1rem;
  color: var(--color-text-secondary);
  white-space: nowrap;
}

/* ─── Main content ──────────────────────────────────────── */
#app {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--spacing-md);
  transition: opacity 360ms ease-out;
}
/* Snap-to-invisible behind the cover panels during a route transition.
   When the class is removed (at the start of exit), #app fades back
   to opacity 1 — that's the "game fades in" cross-fade. */
#app.is-route-hidden {
  opacity: 0;
  transition: none;
}

/* ─── Buttons ───────────────────────────────────────────── */
.btn {
  font-family: var(--font-body);
  font-size: var(--font-size-sm);
  font-weight: 600;
  padding: var(--spacing-xs) var(--spacing-sm);
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color var(--transition-fast), transform var(--transition-fast);
  white-space: nowrap;
}

.btn:active {
  transform: scale(0.97);
}

.btn--primary {
  background-color: var(--color-primary);
  color: var(--color-text-on-primary);
}

.btn--primary:hover {
  background-color: var(--color-primary-hover);
}

.btn--ghost {
  background-color: transparent;
  color: var(--color-text-primary);
  border: 1px solid #9e1817;
}

.btn--ghost:hover {
  background-color: var(--color-surface);
}

/* ─── Round buttons (presenter bar) ────────────────────── */
.round-btn {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  padding: 0.2rem 0.9rem;
  border: 2px solid #9e1817;
  border-radius: var(--radius-sm);
  background-color: transparent;
  color: var(--color-text-primary);
  cursor: pointer;
  transition: all var(--transition-fast);
}

.round-btn.active {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-text-on-primary);
}

.round-btn:hover:not(.active) {
  background-color: var(--color-surface);
  color: var(--color-text-primary);
}

/* ─── Splash screen ─────────────────────────────────────── */
/* Initial frames of the deck. 1920x1080 PNGs dropped into
   public/img/slide1.png, slide2.png, slide3.png, ... scaled by
   fitStage() so they get the same letterbox treatment as the modules
   and the home menu. Space or a left click advances through the slides
   (set inline by app.js); once the next slide is missing, the same input
   dismisses to home. */
.splash-stage-wrap {
  position: fixed;
  top: 3.5rem;
  left: 0;
  right: 0;
  bottom: 0;
  background: #000;
  overflow: hidden;
  z-index: 1;
  user-select: none;
  opacity: 1;
  transition: opacity 1000ms ease;
}

.splash-stage-wrap.is-fading-out {
  opacity: 0;
  pointer-events: none;
}

:fullscreen .splash-stage-wrap {
  top: 0;
}

.splash-stage {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1920px;
  height: 1080px;
  transform-origin: center center;
  transform: translate(-50%, -50%) scale(1);
}

.splash-slide {
  position: absolute;
  inset: 0;
  background-position: center;
  background-size: contain;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 1000ms ease;
}

.splash-slide.is-active {
  opacity: 1;
}

/* ─── Home screen (gameshow stage) ──────────────────────── */
/* Uses the same visual language *and* the same 1920x1080 fixed design
   surface as the Millionaire / Deal / Higher-Lower modules. The wrap
   fills the viewport below the presenter bar with a black background;
   the inner stage is uniformly scaled by fitStage() (utils.js) so the
   menu keeps its 16:9 aspect ratio with letterbox/pillarbox bars on
   off-ratio displays — matching the in-game look. */

.home-stage-wrap {
  --g-gold: #9e1817;
  --g-gold-deep: #6b0f10;
  --g-red: #9e1817;
  --g-blue: #9e1817;
  --g-ink: #000000;
  --g-ink-2: #1a1a1a;
  --g-cream: #FFFFFF;

  position: fixed;
  top: 3.5rem;
  left: 0;
  right: 0;
  bottom: 0;
  background: #000;
  overflow: hidden;
  z-index: 1;
  font-family: 'Oswald', sans-serif;
  color: #000000;
  user-select: none;
}

.home-stage-wrap *,
.home-stage-wrap *::before,
.home-stage-wrap *::after {
  box-sizing: border-box;
}

.home-stage {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1920px;
  height: 1080px;
  transform-origin: center center;
  transform: translate(-50%, -50%) scale(1);
  padding: 0 140px;
  background: url('/img/background.png') center/cover no-repeat, #FFFFFF;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.home-stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse at center, black 40%, transparent 90%);
          mask-image: radial-gradient(ellipse at center, black 40%, transparent 90%);
}

/* ── Main content ─────────────────────────────────────── */
.home-content {
  position: relative;
  z-index: 3;
  flex: 1;
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 40px 0 60px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 40px;
}

.home-title {
  font-family: 'Archivo Black', sans-serif;
  font-size: 96px;
  letter-spacing: 0.08em;
  color: var(--g-ink);
  text-align: center;
  text-shadow: none;
  line-height: 1.05;
  margin: 0;
  text-wrap: balance;
  animation: gs-slide-in-down 700ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
.home-title__accent {
  color: var(--g-gold-deep);
  display: inline-block;
  animation: gs-pop-in 800ms cubic-bezier(0.34, 1.56, 0.64, 1) 220ms both;
}

.home-subtitle {
  font-family: 'Oswald', sans-serif;
  font-weight: 500;
  font-size: 24px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: center;
  color: var(--g-ink);
  opacity: 0.75;
  margin: -16px 0 0;
  animation: gs-slide-in-up 600ms ease-out 380ms both;
}

/* ── Score panel ──────────────────────────────────────── */
.home-score {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 18px 40px;
  background: #FFFFFF;
  border: 3px solid var(--g-gold);
  border-radius: 8px;
  box-shadow:
    0 0 0 2px rgba(0, 0, 0, 0.25),
    0 0 0 6px rgba(0, 0, 0, 0.25),
    0 8px 0 rgba(0, 0, 0, 0.25);
  max-width: 560px;
  margin: 0 auto;
  width: 100%;
  animation: gs-slide-in-right 600ms cubic-bezier(0.22, 1, 0.36, 1) 460ms both;
}
.home-score__label {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 28px;
  letter-spacing: 0.3em;
  color: var(--g-gold);
}
.home-score__value {
  font-family: 'Archivo Black', sans-serif;
  font-size: 48px;
  color: #000000;
  line-height: 1;
  min-width: 120px;
  text-align: center;
  text-shadow: none;
}
.home-score__reset {
  font-family: 'Archivo Black', sans-serif;
  font-size: 14px;
  letter-spacing: 0.18em;
  padding: 8px 18px;
  background: transparent;
  color: #000000;
  border: 2px solid var(--g-gold);
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}
.home-score__reset:hover {
  background: var(--g-gold);
  color: #FFFFFF;
}

/* ── Round selector ───────────────────────────────────── */
.home-round-selector {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  animation: gs-slide-in-left 600ms cubic-bezier(0.22, 1, 0.36, 1) 540ms both;
}
.home-round-selector__label {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 22px;
  letter-spacing: 0.45em;
  color: var(--g-ink);
}
.home-round-selector__buttons {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  justify-content: center;
}
.home-round-btn {
  font-family: 'Archivo Black', sans-serif;
  font-size: 22px;
  letter-spacing: 0.18em;
  color: #000000;
  padding: 14px 48px;
  background: #FFFFFF;
  border: 3px solid rgba(158, 24, 23, 0.4);
  border-radius: 6px;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
  box-shadow:
    0 0 0 2px rgba(0, 0, 0, 0.25),
    0 6px 0 rgba(0, 0, 0, 0.25),
    inset 0 2px 0 rgba(0, 0, 0, 0.25);
}
.home-round-btn:hover:not(.is-active) {
  transform: translateY(-2px);
  border-color: var(--g-gold);
  box-shadow:
    0 0 0 2px rgba(0, 0, 0, 0.25),
    0 8px 0 rgba(0, 0, 0, 0.25),
    0 10px 0 rgba(0, 0, 0, 0.25),
    inset 0 2px 0 rgba(0, 0, 0, 0.25);
}
.home-round-btn.is-active {
  background: var(--g-gold);
  color: #FFFFFF;
  border-color: var(--g-gold);
  box-shadow:
    0 0 0 2px rgba(0, 0, 0, 0.25),
    0 0 0 4px rgba(0, 0, 0, 0.25),
    0 6px 0 rgba(0, 0, 0, 0.25),
    0 0 0 rgba(0, 0, 0, 0.25),
    inset 0 2px 0 rgba(0, 0, 0, 0.25);
}

/* ── Module cards ─────────────────────────────────────── */
.home-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 20px;
  margin-top: 8px;
}
.home-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 20px 18px 18px;
  background: #FFFFFF;
  border: 3px solid rgba(158, 24, 23, 0.35);
  border-radius: 8px;
  cursor: pointer;
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
  box-shadow:
    0 0 0 2px rgba(0, 0, 0, 0.25),
    0 8px 0 rgba(0, 0, 0, 0.25),
    inset 0 2px 0 rgba(0, 0, 0, 0.25),
    inset 0 -20px 0 rgba(0, 0, 0, 0.25);
  overflow: hidden;
  animation: gs-slide-in-up 0ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
  animation-delay: 0ms;
}
.home-card::before { z-index: 2; }
.home-card > * { position: relative; z-index: 1; }
/* Diagonal shine sweep across the card on hover/focus. */
.home-card .home-card__shine {
  position: absolute;
  top: -20%;
  left: 0;
  width: 60%;
  height: 140%;
  background: linear-gradient(
    100deg,
    transparent 0%,
    rgba(255, 255, 255, 0.55) 45%,
    rgba(255, 255, 255, 0.9) 50%,
    rgba(255, 255, 255, 0.55) 55%,
    transparent 100%
  );
  filter: blur(2px);
  transform: translateX(-180%) skewX(-22deg);
  pointer-events: none;
  z-index: 0;
}
.home-card:hover .home-card__shine,
.home-card:focus-visible .home-card__shine {
  animation: gs-shine-sweep 800ms ease-out;
}
.home-card::after {
  content: "";
  position: absolute;
  inset: 5px;
  border: 1px solid rgba(158, 24, 23, 0.15);
  border-radius: 3px;
  pointer-events: none;
}
.home-card::before {
  content: "";
  position: absolute;
  top: -10px;
  left: -10px;
  width: 16px;
  height: 16px;
  background: var(--g-gold);
  border: 3px solid var(--g-gold-deep);
  border-radius: 50%;
  box-shadow: 0 0 0 rgba(0, 0, 0, 0.25);
}
.home-card:hover,
.home-card:focus-visible {
  outline: none;
  transform: translateY(-4px);
  border-color: var(--g-gold);
  box-shadow:
    0 0 0 2px rgba(0, 0, 0, 0.25),
    0 12px 0 rgba(0, 0, 0, 0.25),
    0 18px 0 rgba(0, 0, 0, 0.25),
    inset 0 2px 0 rgba(0, 0, 0, 0.25),
    inset 0 -20px 0 rgba(0, 0, 0, 0.25);
}
.home-card__title {
  font-family: 'Archivo Black', sans-serif;
  font-size: 18px;
  letter-spacing: 0.06em;
  color: #000000;
  text-transform: uppercase;
  text-shadow: none;
  margin: 0;
  text-wrap: balance;
}
.home-card__play-btn {
  margin-top: 2px;
  padding: 8px 22px;
  font-family: 'Archivo Black', sans-serif;
  font-size: 14px;
  letter-spacing: 0.2em;
  color: #FFFFFF;
  background: var(--g-gold);
  border: 2px solid var(--g-gold-deep);
  border-radius: 6px;
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.25), inset 0 2px 0 rgba(0, 0, 0, 0.25);
}

/* ─── Reduce motion toggle (home menu, bottom-right) ───── */
/* Subtle escape hatch for photosensitive audiences. Lives inside
   .home-stage-wrap (outside the scaled stage) so it stays at fixed
   screen-pixel size in the corner. */
.home-anim-toggle {
  position: absolute;
  right: 18px;
  bottom: 14px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.78);
  font-family: 'Oswald', sans-serif;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  z-index: 10;
  transition: opacity 200ms ease, color 200ms ease, border-color 200ms ease;
  opacity: 0.55;
}
.home-anim-toggle:hover,
.home-anim-toggle:focus-visible {
  opacity: 1;
  color: #FFFFFF;
  border-color: rgba(255, 255, 255, 0.45);
  outline: none;
}
.home-anim-toggle__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #4cc66f;
  box-shadow: 0 0 6px rgba(76, 198, 111, 0.6);
}
.home-anim-toggle[aria-pressed="true"] .home-anim-toggle__dot {
  background: #c8c3b9;
  box-shadow: none;
}

/* Kill switch — when set, suppress every CSS animation and transition
   in the app. Module-level setTimeouts still fire, but the visual
   effects snap rather than flash. */
body.no-anim *,
body.no-anim *::before,
body.no-anim *::after {
  animation-duration: 0ms !important;
  animation-delay: 0ms !important;
  transition-duration: 0ms !important;
  transition-delay: 0ms !important;
}


.shortcut-overlay {
  position: fixed;
  bottom: var(--spacing-md);
  right: var(--spacing-md);
  background-color: rgba(0, 0, 0, 0.97);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  max-width: 420px;
  z-index: 200;
  font-size: var(--font-size-sm);
  color: var(--color-text-on-primary);
  box-shadow: 0 8px 0 rgba(0, 0, 0, 0.25);
}

.shortcut-overlay.hidden {
  display: none;
}

.shortcut-overlay__title {
  font-family: var(--font-display);
  font-size: var(--font-size-md);
  font-weight: 700;
  margin-bottom: var(--spacing-sm);
  color: var(--color-accent);
}

.shortcut-list {
  list-style: none;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--spacing-xs) var(--spacing-sm);
  align-items: center;
}

.shortcut-key {
  font-family: monospace;
  background-color: var(--color-surface-raised);
  padding: 0.15rem 0.5rem;
  border-radius: 4px;
  color: var(--color-accent);
  font-weight: 700;
  font-size: 1rem;
  white-space: nowrap;
}

/* ─── Route transition overlay (sports-broadcast wipe) ─── */
/* Two angled panels (red / white) swoosh in from opposite corners
   and meet in the middle. Logo punches in as they collide, then the
   panels fade out in place to reveal the new content — no reverse
   sweep, which would read as a second flash. Sits above everything
   during the transition (z-index: 1000). */
.route-transition {
  position: fixed;
  inset: 0;
  z-index: 1000;
  pointer-events: none;
  background: transparent;
  overflow: hidden;
}

/* Base: panels off-screen with NO transition. Without this, removing
   .is-active / .is-exiting at the end of the transition would let the
   properties revert to base over a 540ms transition — visible as a
   trailing sweep after the cross-fade. The transition is defined only
   on the .is-active rule below, so removing it cleanly snaps the
   panels back to off-screen. */
.route-transition::before,
.route-transition::after {
  content: "";
  position: absolute;
  width: 160%;
  height: 100%;
  top: 0;
  transform: translateX(-120%) skewX(-18deg);
  will-change: transform, opacity;
}

.route-transition::before {
  left: -30%;
  background: linear-gradient(135deg, #c81d1c 0%, #9e1817 45%, #6b0f10 100%);
  box-shadow: 0 0 80px rgba(0, 0, 0, 0.5);
}

.route-transition::after {
  right: -30%;
  transform: translateX(120%) skewX(-18deg);
  background: linear-gradient(135deg, #ffffff 0%, #f5f5f5 60%, #eeeeee 100%);
  box-shadow: 0 0 80px rgba(0, 0, 0, 0.35);
}

.route-transition.is-active {
  pointer-events: auto;
}

/* Sweep in: transition only defined while .is-active is set. */
.route-transition.is-active::before,
.route-transition.is-active::after {
  transform: translateX(0) skewX(-18deg);
  opacity: 1;
  transition: transform 540ms cubic-bezier(0.7, 0, 0.2, 1);
}
.route-transition.is-active::after {
  transition-delay: 60ms;
}

/* Exit: panels snap to invisible. The reveal is carried by #app
   fading from opacity 0 — no panel motion. */
.route-transition.is-exiting::before,
.route-transition.is-exiting::after {
  transform: translateX(0) skewX(-18deg);
  transition: none;
  opacity: 0;
}

.route-transition__logo {
  position: relative;
  width: 300px;
  height: 300px;
  background-image: url('/img/logo.png');
  background-position: center;
  background-size: contain;
  background-repeat: no-repeat;
  margin: 0 auto;
  top: 50%;
  transform: translateY(-50%) scale(0.4);
  opacity: 0;
  filter: drop-shadow(0 8px 0 rgba(0, 0, 0, 0.4)) drop-shadow(0 0 24px rgba(255, 255, 255, 0.3));
  z-index: 2;
}

/* Logo punch-in: transition only defined while .is-active. Removing
   the class snaps the logo back to base — no trailing scale/fade. */
.route-transition.is-active .route-transition__logo {
  opacity: 1;
  transform: translateY(-50%) scale(1);
  transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1) 220ms,
              opacity 200ms ease 220ms;
}

.route-transition.is-exiting .route-transition__logo {
  opacity: 0;
  transform: translateY(-50%) scale(1);
  transition: none;
}

/* Diagonal scanline accent — adds the lower-third vibe. */
.route-transition::before,
.route-transition::after {
  background-blend-mode: normal;
}

.route-transition__logo::after {
  content: "";
  position: absolute;
  inset: -10%;
  background:
    repeating-linear-gradient(
      135deg,
      transparent 0px,
      transparent 8px,
      rgba(0, 0, 0, 0.05) 8px,
      rgba(0, 0, 0, 0.05) 9px
    );
  pointer-events: none;
  mix-blend-mode: multiply;
  border-radius: 8px;
}

/* ─── Shared gameshow animations ────────────────────────── */
@keyframes gs-slide-in-down {
  from { opacity: 0; transform: translateY(-60px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes gs-slide-in-up {
  from { opacity: 0; transform: translateY(60px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes gs-slide-in-left {
  from { opacity: 0; transform: translateX(-100px) skewX(-6deg); }
  to   { opacity: 1; transform: translateX(0) skewX(0); }
}
@keyframes gs-slide-in-right {
  from { opacity: 0; transform: translateX(100px) skewX(6deg); }
  to   { opacity: 1; transform: translateX(0) skewX(0); }
}
@keyframes gs-pop-in {
  0%   { opacity: 0; transform: scale(0.5) rotate(-4deg); }
  60%  { opacity: 1; transform: scale(1.08) rotate(1deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}
@keyframes gs-bar-wipe {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes gs-flash {
  0%   { opacity: 0; transform: scale(0.6); filter: brightness(1.4); }
  40%  { opacity: 1; transform: scale(1.05); filter: brightness(1.2); }
  100% { opacity: 1; transform: scale(1); filter: brightness(1); }
}
@keyframes gs-shine-sweep {
  0%   { transform: translateX(-150%) skewX(-22deg); }
  100% { transform: translateX(250%) skewX(-22deg); }
}
@keyframes gs-glow-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(158, 24, 23, 0.55); }
  50%      { box-shadow: 0 0 0 18px rgba(158, 24, 23, 0); }
}
@keyframes gs-jolt {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-8px) rotate(-0.6deg); }
  40% { transform: translateX(8px) rotate(0.6deg); }
  60% { transform: translateX(-5px); }
  80% { transform: translateX(5px); }
}

/* Shine sweep utility — apply to any element with overflow:hidden.
   Use as an ::after via a wrapper if needed; or via the .gs-shine class. */
.gs-shine {
  position: relative;
  overflow: hidden;
}
.gs-shine::before {
  content: "";
  position: absolute;
  top: -20%;
  left: 0;
  width: 50%;
  height: 140%;
  background: linear-gradient(
    100deg,
    transparent 0%,
    rgba(255, 255, 255, 0.55) 45%,
    rgba(255, 255, 255, 0.85) 50%,
    rgba(255, 255, 255, 0.55) 55%,
    transparent 100%
  );
  filter: blur(2px);
  transform: translateX(-150%) skewX(-22deg);
  pointer-events: none;
  z-index: 1;
}
.gs-shine.is-shining::before,
.gs-shine:hover::before {
  animation: gs-shine-sweep 900ms ease-out;
}

/* Reduced motion — respect users who'd rather have less movement. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ─── Fullscreen: hide presenter bar ───────────────────── */
:fullscreen #presenter-bar {
  display: none;
}
:fullscreen .home-stage-wrap {
  top: 0;
}

/* ─── Fullscreen gate ───────────────────────────────────── */
/* Forces the app into fullscreen: covers and blocks everything while the
   document is windowed, then hidden purely via :fullscreen the moment
   fullscreen is active (same mechanism as the presenter bar above).
   app.js adds .fs-unsupported when the browser has no Fullscreen API so
   an unsupported browser can't lock the operator out entirely. */
.fullscreen-gate {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--spacing-md);
  background: rgba(0, 0, 0, 0.97);
}

:fullscreen .fullscreen-gate,
.fullscreen-gate.fs-unsupported {
  display: none;
}

.fullscreen-gate__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-sm);
  max-width: 640px;
}

.fullscreen-gate__icon {
  font-size: 5rem;
  line-height: 1;
  color: var(--color-accent);
}

.fullscreen-gate__title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--font-size-xl);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-neutral);
}

.fullscreen-gate__text {
  font-size: var(--font-size-md);
  color: rgba(255, 255, 255, 0.8);
  max-width: 32ch;
}

.fullscreen-gate__btn {
  margin-top: var(--spacing-sm);
  font-size: var(--font-size-md);
  padding: var(--spacing-sm) var(--spacing-lg);
}

.fullscreen-gate__hint {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  font-size: var(--font-size-sm);
  color: rgba(255, 255, 255, 0.6);
}

/* ─── Two-screen: presenter / audience ──────────────────── */
/* The app runs in two windows on one machine. The presenter window
   (default) keeps the control bar, a live clock and an answer-key HUD;
   the audience window (?role=audience) shows only the clean board. */

.presenter-bar__clock {
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--color-primary);
  white-space: nowrap;
  letter-spacing: 0.04em;
}

/* Presenter-only answer-key / cue card, pinned out of the stage so it's
   always legible regardless of stage scaling. Hidden by default — it only
   appears once an audience window has connected (body.has-audience), so a
   classic single-screen show never reveals the answer to the room. */
.presenter-hud {
  position: fixed;
  left: var(--spacing-sm);
  bottom: var(--spacing-sm);
  z-index: 2500;
  max-width: 30rem;
  padding: 0.6rem 0.85rem;
  background: rgba(12, 14, 22, 0.9);
  color: #fff;
  border: 2px solid var(--color-primary);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.35;
  pointer-events: none;
  display: none;
}
body.role-presenter.has-audience .presenter-hud:not(:empty) { display: block; }
.presenter-hud__answer strong { color: #ffd34d; }

/* Audience screen: hide all presenter chrome and input affordances. */
body.role-audience #presenter-bar,
body.role-audience .presenter-hud { display: none; }
body.role-audience #app { pointer-events: none; cursor: none; }
body.role-audience .mcq-confirm-zone,
body.role-audience .hl-confirm-zone { visibility: hidden; }
/* Presenter-only cheat panels must never appear on the audience board. */
body.role-audience #hl-answer-key,
body.role-audience #hl-scoreboard { display: none !important; }

/* ─── Utility ───────────────────────────────────────────── */
.hidden { display: none !important; }
