/* Launcher + shared chrome styles */

/* --- Header --- */

.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-height);
  padding-top: var(--safe-area-top);
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding-inline: var(--space-sm);
  z-index: 100;
  gap: var(--space-sm);
}

/* v0.4.31: title position-absolute centered to the VIEWPORT, not to the
 * remaining flex space. Before this fix, .header-title { flex:1; text-align:center }
 * placed the text box in the leftover area between left and right children;
 * since the right cluster (menu + version pill) is wider than the lone left
 * back button, the title centered inside an asymmetric box, shifted left of
 * viewport center. Tests/layout.spec.js asserts title midpoint within
 * 24px of viewport midpoint.
 *
 * pointer-events:none on the wrapper lets clicks pass through to underlying
 * children (turn-indicator etc.) that share its space.
 */
.header > .header-title {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  flex: none;
  margin: 0 auto;
  max-width: calc(100% - 220px);
  pointer-events: none;
}
.header > .header-title > * {
  pointer-events: auto;
}

/* The flex children that sit on either side of the title need their own
 * fixed widths so the back button stays at the far left and the right
 * cluster (turn / menu / version) floats to the far right via
 * margin-left: auto on .header-right. */
.header > .header-back,
.header > .header-menu {
  flex: 0 0 auto;
}
.header-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex: 0 0 auto;
}

.header-logo {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1;
  padding-left: var(--space-sm);
}

.wordmark-top {
  font-family: var(--font-wordmark-top);
  /* Shadows Into Light ships at 400 only. Faux-bold synthesis would distort the
   * painted-handwritten character of the strokes; use the natural weight. */
  font-weight: 400;
  /* 1.7rem matches the picked size from wordmark-comparison.html. Slightly
   * larger than a typical UI display size to compensate for Shadows Into Light's
   * thinner strokes. */
  font-size: 1.7rem;
  color: #ffffff;
}

.wordmark-bottom {
  font-family: var(--font-wordmark-bottom);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
}

.wm-with { color: #8a7bbd; }
.wm-you { color: #a78bfa; }

.header-title {
  text-align: center;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
}

.header-game-icon {
  margin-right: var(--space-xs);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5em;
  height: 1.5em;
  vertical-align: -0.35em;
}

/* v0.4.29 screen-shell: menu + version pill land on every non-launcher screen. */
.header-menu {
  /* Shares .header-btn sizing; explicit class for the layout test to find. */
}

/* v0.4.32 screen-shell: 1-click feedback on every non-launcher screen. */
.header-feedback {
  /* Shares .header-btn sizing. Auto-attaches currentGameId to the report
   * via showFeedback(); user reports never lose game context. */
}
.header-version {
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  margin-right: var(--space-xs);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-tertiary);
  cursor: pointer;
  transition: border-color var(--motion-duration) var(--motion-ease),
              color var(--motion-duration) var(--motion-ease);
  flex: 0 0 auto;
}
.header-version:hover,
.header-version:focus-visible {
  border-color: var(--border-strong, var(--text-tertiary));
  color: var(--text-secondary);
  outline: none;
}
.header-game-icon img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.header-spacer {
  width: 44px;
}

.header-turn {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
  min-width: 44px;
  text-align: right;
  padding-right: var(--space-sm);
}

.header-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  background: none;
  border: none;
  color: var(--text-secondary);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--motion-duration-fast) var(--motion-ease);
  -webkit-tap-highlight-color: transparent;
}

.header-btn:active {
  color: var(--text-primary);
}

/* --- Launcher --- */

.launcher {
  padding-top: calc(var(--header-height) + var(--safe-area-top) + var(--space-md));
  padding-bottom: calc(var(--safe-area-bottom) + var(--space-xl));
  padding-inline: var(--space-md);
  height: 100vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Track 2 (v0.5.5): soft seasonal-sky tint at the top so the painted
   * launcher cards breathe the same atmosphere as their hero scenes. The
   * tint fades to transparent before the first row of cards so the chrome
   * stays mostly --bg flat. References --season-sky so a seasonal palette
   * swap propagates without touching this rule. */
  background-image: radial-gradient(
    ellipse 120% 320px at 50% 0%,
    color-mix(in srgb, var(--season-sky) 14%, transparent) 0%,
    transparent 70%
  );
  background-repeat: no-repeat;
}

/* Resume card (B.4 Default app state Layer 1; Phase C Wave 5c) */
.resume-card {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  max-width: 600px;
  margin: 0 auto var(--space-md);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--card-accent, var(--accent));
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

@media (min-width: 768px) {
  .resume-card {
    max-width: 900px;
  }
}

.resume-card__icon {
  font-size: 2rem;
  line-height: 1;
  flex-shrink: 0;
  /* Track 6 (v0.5.9) painted-floor bump: 3rem (~48px) was below the 64px
   * painted-character floor per docs/visual-dna.md. Bumped to 4rem (~64px)
   * so the painted launcher card thumbnail reads its painted character. */
  width: 4rem;
  height: 4rem;
  border-radius: var(--radius-sm);
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.resume-card__icon img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.resume-card__body {
  flex: 1;
  min-width: 0;
}

.resume-card__eyebrow {
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  color: var(--text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.resume-card__title {
  font-size: var(--text-lg);
  font-family: var(--font-display);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
  margin-top: 2px;
}

.resume-card__desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin-top: 2px;
}

.resume-card__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  flex-shrink: 0;
}

.resume-card__actions .btn {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--text-sm);
  border-radius: var(--radius-sm);
  white-space: nowrap;
  min-height: var(--touch-target-min);
}

/* Recently-played-with-partner row (B.4 Default app state Layer 2; Phase C Wave 6) */
.recently-played {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  max-width: 600px;
  margin: 0 auto var(--space-md);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: transform var(--motion-duration) var(--motion-ease), background var(--motion-duration) var(--motion-ease);
}

.recently-played:hover,
.recently-played:focus-visible {
  background: var(--bg-elevated);
}

.recently-played:active {
  transform: scale(0.99);
}

@media (min-width: 768px) {
  .recently-played {
    max-width: 900px;
  }
}

.recently-played__icon {
  font-size: 1.75rem;
  line-height: 1;
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.recently-played__icon img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.recently-played__body {
  flex: 1;
  min-width: 0;
}

.recently-played__eyebrow {
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  color: var(--card-accent, var(--text-tertiary));
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.recently-played__title {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--text-primary);
  margin-top: 2px;
}

.recently-played__desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin-top: 2px;
}

.recently-played__pill {
  flex-shrink: 0;
  align-self: center;
  padding: var(--space-xs) var(--space-sm);
  background: var(--card-accent, var(--accent));
  color: var(--bg);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  border-radius: 999px;
  white-space: nowrap;
  letter-spacing: 0.01em;
}

/* Intent filter chips (B.3 nav-framework; v0.4.33 polished as proper tabs).
 * Container is a continuous pill segmented bar; selected chip pops via
 * accent fill + drop-shadow. Replaces v0.4.29 floating-chips look. */
.intent-chips {
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding: 4px;
  margin: 0 auto var(--space-lg);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  box-shadow: var(--shadow-sm);
  max-width: max-content;
}

.intent-chips-wrap {
  display: flex;
  justify-content: center;
  padding-inline: var(--space-sm);
}

.intent-chip {
  padding: var(--space-xs) var(--space-lg);
  min-height: 36px;
  background: transparent;
  border: none;
  border-radius: 999px;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  font-weight: var(--font-weight-bold);
  cursor: pointer;
  transition: background var(--motion-duration) var(--motion-ease),
              color var(--motion-duration) var(--motion-ease),
              box-shadow var(--motion-duration) var(--motion-ease);
}

.intent-chip:hover,
.intent-chip:focus-visible {
  color: var(--text-primary);
  outline: none;
}

.intent-chip--active {
  background: var(--accent);
  color: var(--bg);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--accent) 40%, transparent);
}

@media (min-width: 768px) {
  .intent-chips {
    max-width: 900px;
  }
}

.game-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--card-gap);
  max-width: 600px;
  margin: 0 auto;
}

@media (min-width: 768px) {
  .game-grid {
    grid-template-columns: repeat(3, 1fr);
    max-width: 900px;
  }
}

/* Launcher tier sections (V1 readiness audit, 2026-05-01).
 * Featured tier holds the launch slate. Quick Plays tier reframes
 * single-tap utilities so a 30-second loop reads as a feature, not a
 * disappointment. Coming Soon tier holds built:false placeholders.
 * Each section is a separate <div class="game-grid"> preceded by an
 * <h2 class="launcher-section-header">. */
.launcher-section-header {
  font-family: var(--font-script, 'Caveat'), cursive;
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--text-primary);
  text-align: center;
  margin: 1.5rem 0 0.5rem;
  letter-spacing: 0.02em;
}

.launcher-section-header:first-of-type {
  margin-top: 0.5rem;
}

@media (min-width: 768px) {
  .launcher-section-header {
    font-size: 1.75rem;
    margin-top: 2rem;
  }
}

/* Quick Plays tier: visually distinct from Featured (slightly muted)
 * to signal "utility, not game" at first glance. */
.game-grid--quick .game-card {
  opacity: 0.95;
}

/* Intent filter: hide games that don't match the active filter. */
/* Per-filter rules composable with the existing .game-card styles. */
.launcher[data-filter="solo"] .game-card[data-supports-solo="false"] {
  display: none;
}
.launcher[data-filter="multi"] .game-card[data-supports-multi="false"] {
  display: none;
}

/* --- Settings tabs (B.3 standardized tab order; Phase C Wave 5b) --- */
.settings-tabs {
  display: flex;
  gap: var(--space-xs);
  margin-bottom: var(--space-md);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.settings-tab {
  padding: var(--space-sm) var(--space-md);
  min-height: var(--touch-target-min);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-family: var(--font-sans);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--motion-duration) var(--motion-ease),
              border-color var(--motion-duration) var(--motion-ease);
}

.settings-tab:hover,
.settings-tab:focus-visible {
  color: var(--text-primary);
  outline: none;
}

.settings-tab--active {
  color: var(--text-primary);
  border-bottom-color: var(--accent);
}

.settings-panels {
  display: block;
}

.settings-panel {
  display: block;
}
.settings-panel[hidden] {
  display: none;
}

/* Settings sections (grouping within a panel; Phase C Wave 5d) */
.settings-section {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--border);
}

.settings-section__header {
  font-size: var(--text-sm);
  font-family: var(--font-display);
  font-weight: var(--font-weight-bold);
  color: var(--text-primary);
  margin-bottom: var(--space-sm);
}

.settings-hint {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  margin-top: var(--space-sm);
  line-height: var(--line-height-relaxed);
}

/* Flair chips (C.2 Flair System; Phase C Wave 8). Earned vs cosmetic is
   distinguished by color + an "earned" / "cosmetic" marker so cosmetic flair
   can never masquerade as contribution recognition (philosophy Promise #12). */
.flair-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-sm);
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.flair-chip--earned {
  background: color-mix(in srgb, var(--game-accent) 20%, var(--bg-elevated));
  color: var(--game-accent);
  border: 1px solid var(--game-accent);
}

.flair-chip--earned::before {
  content: '\2605';  /* ★ */
  font-size: var(--text-sm);
  line-height: 1;
}

.flair-chip--cosmetic {
  background: var(--bg-elevated);
  color: var(--text-secondary);
  border: 1px solid var(--border);
}

.flair-chip--cosmetic::before {
  content: '\2728';  /* ✨ */
  font-size: var(--text-sm);
  line-height: 1;
}

/* v0.5.29 (C.2 closure): per-tier visual treatment. Each tier overrides
 * the base `--earned` chip with its own color + icon. Tier classes are
 * additive: `<span class="flair-chip flair-chip--earned flair-chip--tier-bug-catcher">`.
 * Per the contract (.studio/practices/flair-system.md): tiers are
 * declared in the studio philosophy, not embedded here; this CSS only
 * provides the visual treatment for the currently-declared set. */

/* Field tester - subtle green (matches color-success token). Subtle
 * because every reader-of-feedback gets it; needs to stay quiet. */
.flair-chip--tier-field-tester {
  background: color-mix(in srgb, var(--color-success, #22c55e) 18%, var(--bg-elevated));
  color: var(--color-success, #22c55e);
  border-color: var(--color-success, #22c55e);
}
.flair-chip--tier-field-tester::before {
  content: '\2713';  /* ✓ */
}

/* Bug catcher - amber. Distinctive: confirmed bug fixed is non-trivial. */
.flair-chip--tier-bug-catcher {
  background: color-mix(in srgb, var(--color-warning, #f59e0b) 22%, var(--bg-elevated));
  color: var(--color-warning, #f59e0b);
  border-color: var(--color-warning, #f59e0b);
}
.flair-chip--tier-bug-catcher::before {
  content: '\1F41B';  /* 🐛 */
  font-size: var(--text-base);
}

/* Idea author - violet/gold (game-accent default). Named flair: shipped
 * suggestion gets credit. Strongest base treatment of the three earnable. */
.flair-chip--tier-idea-author {
  background: color-mix(in srgb, var(--game-accent) 26%, var(--bg-elevated));
  color: var(--game-accent);
  border-color: var(--game-accent);
}
.flair-chip--tier-idea-author::before {
  content: '\1F4A1';  /* 💡 */
  font-size: var(--text-base);
}

/* Founder - era-specific painted accent. Never reissued; visually
 * the most distinctive. Uses the seasonal --summer-sand cream as the
 * border so it reads as a "studio era" not just an action recognition. */
.flair-chip--tier-founder {
  background: color-mix(in srgb, var(--summer-sand, #f0d896) 14%, var(--bg-elevated));
  color: var(--summer-sand, #f0d896);
  border: 1px solid var(--summer-sand, #f0d896);
  font-weight: var(--font-weight-bold);
}
.flair-chip--tier-founder::before {
  content: '\1F33F';  /* 🌿 (painted-natural; era marker not commerce) */
  font-size: var(--text-base);
}

/* Beta tester - cool blue (summer-sky token). Specific to a release;
 * temporary by design. */
.flair-chip--tier-beta-tester {
  background: color-mix(in srgb, var(--summer-sky, #4ba6d6) 18%, var(--bg-elevated));
  color: var(--summer-sky, #4ba6d6);
  border-color: var(--summer-sky, #4ba6d6);
}
.flair-chip--tier-beta-tester::before {
  content: '\1F9EA';  /* 🧪 */
  font-size: var(--text-base);
}

.settings-select {
  min-height: var(--touch-target-min);
  padding: var(--space-xs) var(--space-sm);
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  cursor: pointer;
}

.settings-select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Version pill (B.3 nav-framework persistent chrome; Phase C Wave 5).
   Interactive button that opens the debug panel on tap. Rendered at the
   bottom of the launcher so it's reachable but out of the way. */
.launcher-version {
  display: block;
  margin: var(--space-xl) auto var(--space-md);
  padding: var(--space-xs) var(--space-md);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  cursor: pointer;
  transition: border-color var(--motion-duration) var(--motion-ease),
              color var(--motion-duration) var(--motion-ease);
}

.launcher-version:hover,
.launcher-version:focus-visible {
  border-color: var(--border-strong);
  color: var(--text-secondary);
  outline: none;
}

/* --- Game Card (v0.4.33 hero-card layout) ---
 *
 * Three-zone layout that gives every tile a consistent visual hierarchy:
 *   1. Hero zone (top): per-game atmosphere gradient with the tile image
 *      centered. Uses --game-accent for tinted background so each card
 *      reads as its own world even before bespoke art lands.
 *   2. Body zone (bottom): name, description, mode badge.
 *   3. Hover lift + accent border on focus/hover.
 *
 * The card is a button that fills its grid cell; the hero zone takes
 * roughly 60% of the height, body 40%.
 */

.game-card {
  display: grid;
  grid-template-rows: 1fr auto;
  background: var(--bg-card, var(--bg-surface));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0;
  overflow: hidden;
  cursor: pointer;
  position: relative;
  transition: transform var(--motion-duration-fast) var(--motion-ease),
              border-color var(--motion-duration) var(--motion-ease),
              box-shadow var(--motion-duration) var(--motion-ease),
              background var(--motion-duration) var(--motion-ease);
  -webkit-tap-highlight-color: transparent;
  text-align: left;
  font-family: var(--font-sans);
  min-height: 200px;
  box-shadow: var(--shadow-card);
}

.game-card:active:not(:disabled) {
  transform: scale(0.97);
}

.game-card:not(:disabled):hover,
.game-card:not(:disabled):focus-visible {
  border-color: var(--card-accent, var(--border));
  background: var(--bg-card-hover, var(--bg-elevated));
  box-shadow: var(--shadow-card-hover),
              0 0 0 1px var(--card-accent, transparent),
              0 0 24px color-mix(in srgb, var(--card-accent, var(--accent)) 25%, transparent);
  outline: none;
}

/* v0.4.35 hero zone evolution: when a tile-graphic.png is available
 * (.game-card--has-graphic), the hero zone uses it as a full-bleed
 * background composition with the icon overlaid on top + a dark
 * gradient at the bottom for body-text readability. When no graphic,
 * falls back to the v0.4.33 atmosphere-gradient look. */
.game-card__bg {
  position: absolute;
  inset: 0;
  /* Hero zone fills the top of the card with the asset's natural aspect.
   * Body text sits below. The spacer (.game-card__hero-spacer) reserves
   * the 16:9 footprint so the bg layer (position: absolute) has a known
   * size. v0.4.42 removed the icon overlay entirely; the art IS the
   * visual identity now. */
  bottom: auto;
  /* Match the hero spacer's height (16:9 of card width). */
  aspect-ratio: 16 / 9;
  background-image: var(--card-graphic, none);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  pointer-events: none;
  z-index: 0;
  /* v0.4.42 (Contract D Warm Hero Card): tile-graphic assets are warm,
   * cozy, centered subjects with bottom-fade-to-#0f172a baked in. No CSS
   * opacity / filter / overlay needed. If a renderer has to patch backdrop
   * appearance via CSS, the asset failed the contract; regenerate, do
   * not patch. */
}

/* Reserves the hero zone's 16:9 footprint so the absolute-positioned
 * .game-card__bg has a known size to fill. The body content (title,
 * description, badge) sits below this spacer. */
.game-card__hero-spacer {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
}

.game-card__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: auto;
  min-height: 116px;
  margin: 0;
  padding: var(--space-lg) var(--space-md);
  font-size: var(--card-icon-size);
  line-height: 1;
  position: relative;
  z-index: 1;
  background:
    radial-gradient(ellipse at 50% 35%,
      color-mix(in srgb, var(--card-accent, var(--accent)) 28%, transparent) 0%,
      color-mix(in srgb, var(--card-accent, var(--accent)) 6%, transparent) 55%,
      transparent 100%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--card-accent, var(--accent)) 5%, transparent) 0%,
      transparent 100%);
}

/* When the card has a tile-graphic backdrop, the icon zone goes
 * transparent so the graphic shows through; the icon itself gets a
 * stronger drop-shadow for legibility on top of the photo-like backdrop. */
.game-card--has-graphic .game-card__icon {
  background: transparent;
}
.game-card--has-graphic .game-card__icon img {
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.7))
          drop-shadow(0 0 18px color-mix(in srgb, var(--card-accent, var(--accent)) 50%, transparent));
}

.game-card__icon img {
  width: 88px;
  height: 88px;
  object-fit: contain;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.5))
          drop-shadow(0 0 12px color-mix(in srgb, var(--card-accent, var(--accent)) 35%, transparent));
}

/* Body zone */
.game-card__name {
  font-family: var(--font-display, var(--font-sans));
  font-size: var(--text-lg);
  font-weight: var(--font-weight-display);
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight, -0.02em);
  padding: var(--space-md) var(--space-md) var(--space-xs);
  margin: 0;
  position: relative;
  z-index: 1;
}

.game-card__desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: var(--line-height-normal);
  padding: 0 var(--space-md) var(--space-sm);
  margin: 0;
  position: relative;
  z-index: 1;
}

.game-card__badge {
  font-size: 10px;
  color: var(--text-tertiary);
  background: transparent;
  border: 1px solid var(--border);
  padding: 2px 8px;
  border-radius: 100px;
  margin: 0 var(--space-md) var(--space-md);
  letter-spacing: var(--tracking-wide, 0.04em);
  text-transform: uppercase;
  align-self: start;
  justify-self: start;
  width: max-content;
  position: relative;
  z-index: 1;
}

/* Coming soon */

.game-card--coming-soon {
  opacity: 0.45;
  cursor: default;
  filter: grayscale(0.5);
}
.game-card--coming-soon .game-card__icon {
  background: var(--bg-surface);
}

.game-card__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  color: var(--text-tertiary);
  background: rgba(0, 0, 0, 0.3);
  border-radius: var(--radius);
}

/* --- Mode Select --- */

.mode-select {
  padding-top: calc(var(--header-height) + var(--safe-area-top) + var(--space-lg));
  padding-inline: var(--space-lg);
  padding-bottom: var(--space-xl);
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  max-width: 400px;
  margin: 0 auto;
  min-height: 100%;
  box-sizing: border-box;
}

.mode-btn {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  width: 100%;
  padding: var(--space-sm) var(--space-md);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  min-height: 52px;
  cursor: pointer;
  transition: transform var(--motion-duration-fast) var(--motion-ease),
              border-color var(--motion-duration) var(--motion-ease);
  -webkit-tap-highlight-color: transparent;
}

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

.mode-btn--active {
  border-color: var(--game-accent, var(--accent));
}

.mode-btn__label {
  flex: 1;
  text-align: left;
}

.mode-btn__sub {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

.mode-btn svg {
  color: var(--text-secondary);
}

/* v0.4.34 mode-select redesign: game preview + compact mode picker + dominant Play CTA.
 *
 * The user opened this screen because they tapped a game tile - their
 * intent is to PLAY THE GAME, not configure settings. So the layout
 * leads with the game's hero art, mode picker becomes a compact
 * segmented bar (only shown when more than one mode), settings are
 * inline + minimal, and the Play button is the dominant action.
 */

.mode-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
  max-width: 400px;
  /* v0.5.7 (Track 3.5): no inset padding around the art; the painted hero
   * fills the card top edge-to-edge. Body text gets its own padding below. */
  padding: 0;
  border-radius: var(--radius);
  /* Surface stays opaque per Contract 5 - the painted in-game backdrop must
   * not bleed through. The accent halo lives in the hero zone instead. */
  background: var(--bg-card, var(--bg-surface));
  border: 1px solid var(--border);
  box-shadow: var(--shadow-card);
  margin: 0 auto var(--space-md);
  overflow: hidden;
}
.mode-preview__art {
  /* v0.5.7 (Track 3.5): art zone sized to match the launcher card hero (16:9
   * aspect ratio, full card width). The launcher tile and the mode-select
   * preview now show the same painted scene at the same identity. */
  width: 100%;
  aspect-ratio: 16 / 9;
  display: block;
  margin-bottom: 0;
  position: relative;
  background-size: cover;
  background-position: center;
}
.mode-preview__art img {
  /* When the game has tileGraphic, art is shown via .mode-preview__art's
   * background-image (orchestrator sets --card-graphic). For games without a
   * tileGraphic, the inner img falls back to the icon at a sensible size. */
  width: 96px;
  height: 96px;
  position: absolute;
  inset: 0;
  margin: auto;
  object-fit: contain;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.5));
}
/* When tileGraphic is set, hide the inner img - the painted scene fills the
 * hero zone via background-image and the small img becomes redundant. */
.mode-preview__art--has-graphic img { display: none; }
.mode-preview__body {
  padding: var(--space-lg) var(--space-xl) var(--space-xl);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  /* Subtle accent halo behind title text only (was on the whole card). */
  background:
    radial-gradient(ellipse at 50% 0%,
      color-mix(in srgb, var(--card-accent, var(--accent)) 18%, transparent) 0%,
      transparent 60%);
}
.mode-preview__title {
  font-family: var(--font-display, var(--font-sans));
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-display);
  letter-spacing: var(--tracking-tight, -0.02em);
  color: var(--text-primary);
  margin: 0 0 var(--space-xs);
}
.mode-preview__desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin: 0;
  line-height: var(--line-height-normal);
  max-width: 30ch;
}

.mode-settings {
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
}
.mode-settings:empty { display: none; }

/* Mode commit (Contract 2): pill row of tap-to-commit primary actions.
 * No separate Play button. Tap a pill = start the game in that mode. */
.mode-commit {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  align-self: center;
}
.mode-commit__option,
.mode-commit__solo-only {
  width: 100%;
}

/* CTA primitives (Contract 1: Action Hierarchy).
 * Use these instead of raw .btn for any user-facing action. */
.cta-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  height: 56px;
  padding: 0 var(--space-xl);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-snug, -0.01em);
  background: var(--game-accent, var(--accent));
  color: var(--bg);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 6px 18px color-mix(in srgb, var(--game-accent, var(--accent)) 35%, transparent),
              0 2px 4px rgba(0, 0, 0, 0.35);
  transition: transform var(--motion-duration-fast) var(--motion-ease),
              box-shadow var(--motion-duration) var(--motion-ease);
}
.cta-primary svg { color: currentColor; flex: 0 0 auto; }
.cta-primary:hover,
.cta-primary:focus-visible {
  outline: none;
  box-shadow: 0 10px 26px color-mix(in srgb, var(--game-accent, var(--accent)) 45%, transparent),
              0 2px 4px rgba(0, 0, 0, 0.35);
}
.cta-primary:active {
  transform: scale(0.97);
}

.cta-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  height: 56px;
  padding: 0 var(--space-xl);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 999px;
  cursor: pointer;
  transition: transform var(--motion-duration-fast) var(--motion-ease);
}
.cta-secondary:active {
  transform: scale(0.97);
}

.cta-tertiary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  height: 40px;
  padding: 0 var(--space-md);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-normal);
  background: transparent;
  color: var(--text-secondary);
  border: none;
  cursor: pointer;
}
.cta-tertiary:hover {
  color: var(--text-primary);
}
.mode-select__cta svg { flex: 0 0 auto; }

/* --- Game Container --- */

.game-container {
  position: fixed;
  top: calc(var(--header-height) + var(--safe-area-top));
  left: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
  /* Track 3 (v0.5.6): per-game painted backdrop layer.
   * --in-game-backdrop is set by orchestrator.mountGame() from the registry's
   * inGameBackdrop field. Layered under a dark navy gradient overlay so game
   * pieces still read against the painted scene. Games without the field get
   * background-image: none (falls through to body --bg). The overlay opacity
   * (0.62) was tuned so summer-meadow / summer-shore scenes stay visible but
   * the white text + bright sprites still hit the WCAG-AA contrast budget.
   * Tunable globally via this single value. */
  background-image:
    linear-gradient(rgba(15, 23, 42, 0.62), rgba(15, 23, 42, 0.62)),
    var(--in-game-backdrop, none);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* --- Game Over Overlay --- */

.game-over-overlay {
  position: fixed;
  inset: 0;
  background: var(--overlay-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: var(--space-lg);
  animation: fadeIn var(--motion-duration) var(--motion-ease);
}

.game-over-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--modal-radius);
  padding: var(--modal-padding);
  width: var(--modal-width);
  max-height: calc(100vh - var(--space-xl) * 2);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  text-align: center;
  animation: slideUp var(--motion-duration) var(--motion-spring);
}

.game-over-icon {
  font-size: 48px;
  margin-bottom: var(--space-md);
}

.game-over-message {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--font-weight-display);
  color: var(--text-primary);
  margin-bottom: var(--space-lg);
}

.game-over-stats {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-bottom: var(--space-lg);
}

.game-over-stat {
  display: flex;
  justify-content: space-between;
  font-size: var(--text-sm);
}

.game-over-stat__label { color: var(--text-secondary); }
.game-over-stat__value { color: var(--text-primary); font-weight: var(--font-weight-bold); }

.game-over-actions {
  display: flex;
  gap: var(--space-sm);
}

/* --- Buttons --- */

/* NOTE (v0.4.29): the previous default `flex: 1` here caused .btn to
 * stretch to fill any flex container, producing full-screen buttons in
 * every game that dropped a .btn into a column flex (Dice Roller,
 * Tap Speed, and more). Default is now `flex: 0 0 auto` - explicit
 * opt-in required for stretch. Contexts that still want stretching
 * (resume-card action row, mode-select pair) scope the rule themselves.
 *
 * Games MUST use the `.game-action-btn` primitive from
 * game-primitives.css instead of raw `.btn` for in-game actions, so
 * constraints are enforced by the primitive rather than every call site.
 */
.btn {
  flex: 0 0 auto;
  height: var(--button-height);
  padding: 0 var(--space-xl);
  border: none;
  border-radius: var(--button-radius);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  cursor: pointer;
  transition: transform var(--motion-duration-fast) var(--motion-ease);
  -webkit-tap-highlight-color: transparent;
}

/* Scoped opt-in: side-by-side action rows where buttons should share width. */
.resume-card__actions .btn,
.mode-select .btn,
.game-over-overlay .btn {
  flex: 1 1 0;
  min-width: 0;
}

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

.btn--primary {
  background: var(--game-accent, var(--accent));
  color: var(--bg);
}

.btn--secondary {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

/* --- Error --- */

.error-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  gap: var(--space-lg);
  color: var(--text-secondary);
  font-family: var(--font-sans);
  padding: var(--space-xl);
  text-align: center;
}

/* --- Settings --- */

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-md) 0;
  border-bottom: 1px solid var(--border);
}

.settings-label {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  font-size: var(--text-base);
  color: var(--text-primary);
}

.settings-label svg {
  color: var(--text-secondary);
}

.settings-toggle {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: var(--space-xs) var(--space-md);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  cursor: pointer;
  min-width: 48px;
}

.settings-size-btns {
  display: flex;
  gap: var(--space-xs);
}

.settings-size-btn {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-xs) var(--space-sm);
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  cursor: pointer;
}

.settings-size-btn--active {
  border-color: var(--accent);
  color: var(--text-primary);
}

/* --- Animations --- */

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideUp {
  from { transform: translateY(16px) scale(0.97); opacity: 0; }
  to { transform: translateY(0) scale(1); opacity: 1; }
}
