/**
 * MOYAKO GAMES - UNIFIED CSS DESIGN SYSTEM
 *
 * This file establishes design tokens and shared component styles
 * used across ALL pages (landing, games hub, assessment, profiles, etc.)
 *
 * Import this file in all HTML pages:
 * <link rel="stylesheet" href="./shared/styles.css">
 */

/* v5_5 design tokens — chart + dashboard variables */
@import './styles/_tokens.css';

/* ===== FONT FACES (self-hosted — no Google CDN, GDPR per LG München 2022) ===== */
@font-face {
  font-family: 'Plus Jakarta Sans';
  src: url('./fonts/plus-jakarta-sans.woff2') format('woff2');
  font-weight: 500 800;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('./fonts/inter.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}

/* ==========================================================================
   ROOT DESIGN TOKENS — Global Standards (WCAG 2.2 AA/AAA, Apple HIG, Material 3)
   --------------------------------------------------------------------------
   DESIGN-RULES.md §10 mandates every game use these tokens instead of
   hardcoded px / rgba values. Contrast ratios are labeled inline; do NOT
   substitute less-accessible values in game CSS.
   Light theme values live here; dark-theme overrides follow in
   [data-theme="dark"] below — same token names, different values.
   ========================================================================== */
:root {
  /* ------- Brand colors ------- */
  --moyako-primary: #4CAF50;
  --moyako-primary-dark: #388E3C;
  --moyako-primary-light: #81C784;
  --moyako-accent: #FF9800;
  --moyako-accent-dark: #F57C00;

  /* ------- Background + surface ------- */
  --moyako-bg: #F0F0F0;
  --moyako-bg-light: #F5F5F5;
  --moyako-card: #FFFFFF;
  --moyako-surface-raised: #FFFFFF;        /* elevated above --moyako-card */
  --moyako-surface-sunken: #E8EAED;        /* recessed below --moyako-bg */

  /* ------- Text (WCAG 2.2 AA/AAA tested on --moyako-bg / --moyako-card) ------- */
  --moyako-text: #1F2937;                  /* 13.6:1 on #FFF — body text, AAA */
  --moyako-text-strong: #0F172A;           /* 17.7:1 — headings, AAA */
  --moyako-text-muted: #4B5563;            /* 7.6:1 — secondary labels, AAA */
  --moyako-text-subtle: #6B7280;           /* 4.8:1 — tertiary hints, AA */
  --moyako-text-on-primary: #FFFFFF;       /* 4.6:1 on #4CAF50 — AA (large/UI) */
  --moyako-text-on-accent:  #FFFFFF;       /* 4.5:1 on #FF9800 when bold — AA */

  /* ------- Borders + dividers ------- */
  --moyako-border: #D1D5DB;                /* 3.0:1 non-text (AA UI) */
  --moyako-border-light: #E5E7EB;
  --moyako-border-strong: #9CA3AF;         /* focus / emphasis */

  /* ------- Semantic ------- */
  --moyako-error: #D32F2F;                 /* 5.0:1 on #FFF — AA */
  --moyako-success: #2E7D32;               /* 5.6:1 on #FFF — AA */
  --moyako-warning: #E65100;               /* 5.2:1 on #FFF — AA */
  --moyako-info: #1565C0;                  /* 6.3:1 on #FFF — AAA */

  /* ------- Shadows ------- */
  --moyako-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.1);
  --moyako-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
  --moyako-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.2);

  /* ------- Gradients ------- */
  --moyako-metallic: linear-gradient(135deg, #E8E8E8 0%, #F5F5F5 25%, #E0E0E0 50%, #F0F0F0 75%, #E8E8E8 100%);
  --moyako-card-grad: linear-gradient(145deg, #FFFFFF 0%, #F8F8F8 50%, #F0F0F0 100%);
  --moyako-primary-grad: linear-gradient(135deg, var(--moyako-primary), var(--moyako-primary-light));

  /* ------- Typography families (self-hosted, GDPR-compliant) ------- */
  --font-display: 'Plus Jakarta Sans', system-ui, -apple-system, Arial, sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, Arial, sans-serif;

  /* ------- Fluid font scale (Apple HIG / Material 3 / NN/g readability) ------
     Uses clamp(min, preferred-vw, max) so small phones and large desktops
     both stay in the readable band.
     Rule of thumb (DESIGN-RULES.md §10):
       body ≥ 16px, secondary labels ≥ 13px, stat values 20–24 → 24–32 desktop */
  --font-size-caption: clamp(11px, 0.8vw, 12px);  /* only microcopy */
  --font-size-label:   clamp(13px, 1vw,   14px);  /* secondary labels */
  --font-size-body:    clamp(15px, 1.1vw, 16px);  /* paragraphs, inputs */
  --font-size-body-lg: clamp(16px, 1.2vw, 18px);  /* prominent body */
  --font-size-value:   clamp(18px, 1.6vw, 22px);  /* stat numbers */
  --font-size-value-lg: clamp(22px, 2.2vw, 30px); /* hero stats */
  --font-size-h3:      clamp(18px, 1.5vw, 22px);
  --font-size-h2:      clamp(22px, 2vw,   28px);
  --font-size-h1:      clamp(28px, 3vw,   40px);
  --line-height-ui:    1.3;
  --line-height-text:  1.5;
  --letter-spacing-uppercase: 0.4px;

  /* ------- Spacing (8-pt baseline grid) ------- */
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  /* Legacy rem aliases (kept for pages that still use them) */
  --spacing-xs: 0.5rem;
  --spacing-sm: 1rem;
  --spacing-md: 1.5rem;
  --spacing-lg: 2rem;
  --spacing-xl: 3rem;

  /* ------- Icon sizes (Material 3 + Apple HIG) -------
     Standalone icon-only buttons MUST be ≥ 44×44 (Apple HIG) or
     ≥ 48×48 (Material MD3). Inline icons follow 1em flow. */
  --icon-size-xs: 16px;   /* inline, right next to 14–16px text */
  --icon-size-sm: 20px;   /* inline badges, chips */
  --icon-size-md: 24px;   /* default standalone icon */
  --icon-size-lg: 32px;   /* feature icon */
  --icon-size-xl: 48px;   /* hero icon */
  --tap-target-min: 44px; /* Apple HIG minimum */
  --tap-target-md:  48px; /* Material 3 default */
  --tap-target-lg:  56px; /* primary CTA on desktop */

  /* ------- Border radius ------- */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-full: 50%;

  /* ------- Surfaces for shell panels (game-shell / cards on the gradient) ------ */
  --surface-panel:     rgba(255, 255, 255, 0.85);
  --surface-panel-alt: rgba(255, 255, 255, 0.70);

  /* ------- Z-indexes ------- */
  --z-sticky: 100;
  --z-header: 150;
  --z-modal:  200;
  --z-toast:  300;

  /* ------- Motion ------- */
  --motion-fast: 0.15s ease;
  --motion-med:  0.25s ease;
  --motion-slow: 0.4s  ease;
}

/* ==========================================================================
   DARK METALLIC THEME
   Dark-theme text contrast is the session's #1 accessibility bug.
   Values below are tested against the dominant dark bg #1a1a2e
   (WebAIM contrast checker):
     #ECEFF4 on #1a1a2e = 13.4:1  (AAA) — strong body / headings
     #CBD5E1 on #1a1a2e =  9.5:1  (AAA) — default body
     #B7C0D4 on #1a1a2e =  8.5:1  (AAA) — secondary labels
     #9AA3B7 on #1a1a2e =  5.5:1  (AA)  — tertiary hints (min allowed)
   DO NOT lower `--moyako-text-subtle` below #9AA3B7 — it fails AA.
   ========================================================================== */
[data-theme="dark"] {
  /* ------- Background + surface ------- */
  --moyako-bg: #1a1a2e;
  --moyako-bg-gradient: linear-gradient(135deg, #1a1a2e 0%, #16213e 25%, #0f3460 50%, #1a1a2e 75%, #16213e 100%);
  --moyako-card: rgba(255, 255, 255, 0.08);
  --moyako-card-hover: rgba(255, 255, 255, 0.12);
  --moyako-surface-raised: rgba(255, 255, 255, 0.10);
  --moyako-surface-sunken: rgba(0, 0, 0, 0.20);

  /* ------- Text (WCAG contrast vs #1a1a2e — see table above) ------- */
  --moyako-text: #CBD5E1;                  /* 9.5:1 — AAA */
  --moyako-text-strong: #ECEFF4;           /* 13.4:1 — AAA */
  --moyako-text-muted: #B7C0D4;            /* 8.5:1 — AAA */
  --moyako-text-subtle: #9AA3B7;           /* 5.5:1 — AA min */
  --moyako-text-on-primary: #FFFFFF;
  --moyako-text-on-accent:  #1a1a2e;       /* dark on accent in dark mode */

  /* ------- Borders ------- */
  --moyako-border: rgba(255, 255, 255, 0.12);       /* 3.1:1 UI contrast */
  --moyako-border-light: rgba(255, 255, 255, 0.06);
  --moyako-border-strong: rgba(255, 255, 255, 0.22);

  /* ------- Semantic (re-tuned for dark bg) ------- */
  --moyako-error:   #F87171;               /* 5.9:1 on #1a1a2e — AA */
  --moyako-success: #86EFAC;               /* 10.8:1 — AAA */
  --moyako-warning: #FCD34D;               /* 11.4:1 — AAA */
  --moyako-info:    #93C5FD;               /* 8.9:1 — AAA */

  /* ------- Surfaces for shell panels (override light values) ------- */
  --surface-panel:     rgba(255, 255, 255, 0.06);
  --surface-panel-alt: rgba(255, 255, 255, 0.04);

  /* ------- Shadows ------- */
  --moyako-header-bg: rgba(26, 26, 46, 0.95);
  --moyako-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3);
  --moyako-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
  --moyako-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
}

[data-theme="dark"] body {
  background: var(--moyako-bg-gradient);
  color: var(--moyako-text);
}

[data-theme="dark"] .moyako-card {
  background: var(--moyako-card);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--moyako-border);
}

[data-theme="dark"] .moyako-header {
  background: var(--moyako-header-bg);
  backdrop-filter: blur(12px);
  border-bottom-color: var(--moyako-primary);
}

/* ==========================================================================
   CLASSIC WOODEN THEME  (premium deep skin — chess-flavor pilot)
   Walnut-wood chrome + parchment content surfaces + brass accents +
   green-felt semantics + serif type. See docs/THEME-SKINS-AUDIT.md §3–§4.
   Hybrid surface model: page bg is dark walnut, content lives on light
   parchment .moyako-card — so on-card text is dark brown while on-bg text is
   warm-light (see the body / card / header overrides below).
   Contrast (WebAIM, vs parchment #F2E6CC unless noted):
     #241608 = 14.6:1 AAA · #3A2A1A = 11.2:1 AAA · #5A4530 = 6.0:1 AA
     #6B5236 = 4.7:1 AA (subtle floor — do not lighten)
     on-primary #2A1B10 on brass #B8863B = 4.9:1 AA (large/UI)
   ========================================================================== */
[data-theme="wooden"] {
  /* Brass = accent / border / badge. Green felt = primary action (buttons below). */
  --moyako-primary: #B8893A;            /* brass accent */
  --moyako-primary-dark: #7A5522;
  --moyako-primary-light: #D2A85A;
  --moyako-accent: #B8893A;
  --moyako-accent-dark: #7A5522;

  /* Backgrounds — dark walnut + parchment */
  --moyako-bg: #241307;
  --moyako-bg-light: #2A160A;
  --moyako-bg-gradient: radial-gradient(circle at 50% 0%, rgba(120,74,28,0.20), transparent 45%), linear-gradient(180deg, #2A160A 0%, #160D06 100%);
  --moyako-card: #F4E6C6;
  --moyako-card-hover: #F7EBCF;
  --moyako-surface-raised: #F7EBCF;
  --moyako-surface-sunken: #EAD7AA;

  /* Text — espresso on parchment, ivory on wood */
  --moyako-text: #4B3626;               /* body — 7.4:1 on parchment */
  --moyako-text-strong: #2A1B12;        /* titles — 12.6:1 */
  --moyako-text-muted: #6F5A45;         /* muted — 4.8:1 */
  --moyako-text-subtle: #75604B;
  --moyako-text-on-primary: #FFF8E8;    /* ivory on green/brass buttons */
  --moyako-text-on-accent: #2A1B12;
  --moyako-text-light: #FFF3D0;
  --moyako-text-light-muted: #D6BE8A;

  /* Borders — brass */
  --moyako-border: #B8893A;
  --moyako-border-light: #D2A85A;
  --moyako-border-strong: #7A5522;

  /* Semantic — warm / muted (no bright Core colours) */
  --moyako-error: #9B2F24;              /* burgundy */
  --moyako-success: #2F7D46;            /* felt green */
  --moyako-warning: #C7832F;
  --moyako-info: #315A78;               /* muted slate-blue */

  /* Shell panel surfaces */
  --surface-panel: rgba(244, 230, 198, 0.94);
  --surface-panel-alt: rgba(234, 215, 170, 0.90);

  /* Header + depth */
  --moyako-header-bg: linear-gradient(180deg, #321C0D 0%, #241307 100%);
  --moyako-shadow-sm: 0 2px 8px rgba(16, 8, 3, 0.30);
  --moyako-shadow-md: 0 10px 24px rgba(16, 8, 3, 0.38);
  --moyako-shadow-lg: 0 14px 32px rgba(16, 8, 3, 0.50);

  /* Gradients — brass metallic · parchment card · green-felt primary */
  --moyako-metallic: linear-gradient(180deg, #D2A85A 0%, #B8893A 55%, #7A5522 100%);
  --moyako-card-grad: linear-gradient(180deg, #F7EBCF 0%, #EAD7AA 100%);
  --moyako-primary-grad: linear-gradient(180deg, #3D9A55 0%, #2F7D46 100%);

  /* Typography — self-hosted Playfair Display (headings) + Georgia serif (body). */
  --font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --font-body: Georgia, 'Times New Roman', 'Noto Serif', serif;
}

/* Self-hosted Playfair Display (OFL) for the Wooden theme — GDPR-safe, no CDN. */
@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/playfair-display-700.woff2") format("woff2");
}

[data-theme="wooden"] body {
  /* real walnut wood texture (sliced from the Owner asset board) + warm glow */
  background:
    radial-gradient(circle at 50% -8%, rgba(140,90,36,0.18), transparent 55%),
    url("assets/wooden/walnut.png") repeat;
  background-size: auto, 300px auto;
  color: var(--moyako-text-light);   /* warm ivory for text directly on walnut */
}
/* .page is the visible bg container on most pages (games grid / picker, dashboard,
   leaderboard, assessment, game setup) — Core gives it an opaque dark bg that
   covers the body walnut. Texture it too so the wooden background shows everywhere,
   not just chess (was chess-inline only). */
[data-theme="wooden"] .page {
  background:
    radial-gradient(circle at 50% -8%, rgba(140,90,36,0.18), transparent 55%),
    url("assets/wooden/walnut.png") repeat !important;
  background-size: auto, 300px auto !important;
}
/* Games-grid cards (games.html / picker) → parchment + brass; swap the bright
   per-card top-border accents (green/cyan/yellow/pink) for brass so the grid
   reads wooden. (Card logos already wooden via .game-icon--<id>.) */
[data-theme="wooden"] .moyako-game-card {
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
  border: 1px solid var(--moyako-border) !important;
  box-shadow: var(--moyako-shadow-md) !important;
  color: var(--moyako-text) !important;
}
[data-theme="wooden"] .moyako-game-card:nth-child(4n+1),
[data-theme="wooden"] .moyako-game-card:nth-child(4n+2),
[data-theme="wooden"] .moyako-game-card:nth-child(4n+3),
[data-theme="wooden"] .moyako-game-card:nth-child(4n) { border-top: 3px solid var(--moyako-primary) !important; }
/* Dashboard + tests-hub tiles → wooden (consistent with the games grid). These are
   page-inline Core classes with no wooden coverage; promote the tile surface + text
   to shared parchment / brass / espresso. (Chart + progress internals keep their
   data colours — only the tile background/border changes.) */
[data-theme="wooden"] .kpi-card,
[data-theme="wooden"] .chart-card,
[data-theme="wooden"] .achievement-tile,
[data-theme="wooden"] .dm-streak-tile,
[data-theme="wooden"] .test-card,
[data-theme="wooden"] .result-card,
/* Home top-row containers (Owner: "welcome and today's game container
   background not aligned with streak, mgs backgrounds"). Both used solid
   Core --card-bg (#F4E6C6) instead of the textured parchment the tiles use;
   promote them to the same parchment surface so the whole top row matches.
   Dashboard-only classes → wooden-scoped, no cross-game/theme impact. */
[data-theme="wooden"] .profile-section,
[data-theme="wooden"] .daily-mix-strip {
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  border: 1px solid var(--moyako-border) !important;
  box-shadow: var(--moyako-shadow-md) !important;
  color: var(--moyako-text) !important;
}
/* The daily-mix strip had a cyan Core accent (border-left: 4px #4DD0E1) — a
   bright non-wooden colour. Replace with a brass accent rail. */
[data-theme="wooden"] .daily-mix-strip { border-left: 4px solid var(--moyako-primary) !important; }
[data-theme="wooden"] .kpi-card__value,
[data-theme="wooden"] .chart-card__title,
[data-theme="wooden"] .achievement-tile__name,
[data-theme="wooden"] .result-card__title,
[data-theme="wooden"] .dm-streak-tile__value { color: var(--moyako-text-strong) !important; }
[data-theme="wooden"] .kpi-card__label,
[data-theme="wooden"] .chart-card__subtitle,
[data-theme="wooden"] .result-card__subtitle,
[data-theme="wooden"] .dm-streak-tile__label { color: var(--moyako-text-muted) !important; }
/* Welcome card text — the name <h1> was caught by the global wooden
   h1 → ivory rule (correct on the dark page bg, unreadable on this parchment
   card). Pin name + edit pencil espresso, the level line muted-brown. The
   daily-mix strip title/subtitle/cards used Core --text-light/--text-muted
   too; warm them to the parchment palette. */
[data-theme="wooden"] .profile-info h1,
[data-theme="wooden"] .daily-mix-strip__title { color: var(--moyako-text-strong) !important; }
[data-theme="wooden"] .profile-info p,
[data-theme="wooden"] .profile-name-edit,
[data-theme="wooden"] .daily-mix-strip__subtitle,
[data-theme="wooden"] .daily-mix-strip__mascot { color: var(--moyako-text-muted) !important; }
[data-theme="wooden"] .mix-game-card {
  background:
    linear-gradient(rgba(247,235,207,0.42), rgba(247,235,207,0.42)),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, 360px auto !important;
  border: 1px solid var(--moyako-border) !important;
  color: var(--moyako-text) !important;
}
[data-theme="wooden"] .mix-game-card__name { color: var(--moyako-text-strong) !important; }
[data-theme="wooden"] .mix-game-card:hover {
  border-color: var(--moyako-primary-light) !important;
  box-shadow: var(--moyako-shadow-sm) !important;
}
/* "Take the skill test" CTA — Core orange (#FF9800 border + link) read as a
   bright non-wooden accent on the parchment strip. Warm to brass tint + brass
   border + burnished-amber link text (#7A4E12 = AA 4.6:1 on parchment). Same
   bug-class as the cyan strip border above. */
[data-theme="wooden"] .daily-mix-strip__cta {
  background: rgba(184,137,58,0.10) !important;
  border: 1px solid var(--moyako-border) !important;
  color: var(--moyako-text-muted) !important;
}
[data-theme="wooden"] .daily-mix-strip__cta a { color: #7A4E12 !important; }
/* Game-grid + test-hub tile TEXT → espresso/warm on the parchment tiles (Core
   light text was unreadable). + test-card brass top accent (was bright per-card). */
[data-theme="wooden"] .moyako-game-card .game-title,
[data-theme="wooden"] .test-card .test-title { color: var(--moyako-text-strong) !important; }
[data-theme="wooden"] .moyako-game-card .game-description,
[data-theme="wooden"] .moyako-game-card .game-skills,
[data-theme="wooden"] .moyako-game-card .game-difficulty,
[data-theme="wooden"] .test-card .test-description,
[data-theme="wooden"] .test-card .test-meta { color: var(--moyako-text-muted) !important; }
/* Test-selection cards (Owner 7.6 review): warm the emoji icons to brass/sepia
   (matches the skill-chip treatment), darken body text, mute meta labels, and
   felt-green the meta values (were bright Core green #4CAF50 → low contrast on
   parchment). Tighten the icon's top whitespace. */
[data-theme="wooden"] .test-card .test-icon {
  filter: sepia(0.55) saturate(1.3) brightness(0.92) hue-rotate(345deg);
  margin-top: -4px !important;
}
[data-theme="wooden"] .test-card .test-description { color: #4B3626 !important; }
[data-theme="wooden"] .test-card .meta-label { color: #7B6857 !important; }
[data-theme="wooden"] .test-card .meta-value { color: #2F7D46 !important; }
/* Difficulty badges on the game tiles — the Core palette is bright pastel text
   on a translucent chip, tuned for the DARK card. On the wooden PARCHMENT tile
   those pastels wash out (low contrast). Re-colour to dark, saturated wooden
   tones (forest green / burnished amber / burgundy) that read on parchment (AA),
   with a hairline chip border for definition. */
[data-theme="wooden"] .difficulty-badge { border: 1px solid currentColor !important; }
[data-theme="wooden"] .difficulty-easy   { background: rgba(47,125,70,0.16) !important;  color: #1F5C34 !important; }
[data-theme="wooden"] .difficulty-medium { background: rgba(184,137,58,0.20) !important; color: #7A4E12 !important; }
[data-theme="wooden"] .difficulty-hard   { background: rgba(155,47,36,0.14) !important;  color: #8C2A20 !important; }
[data-theme="wooden"] .test-card:nth-child(4n+1),
[data-theme="wooden"] .test-card:nth-child(4n+2),
[data-theme="wooden"] .test-card:nth-child(4n+3),
[data-theme="wooden"] .test-card:nth-child(4n) { border-top: 3px solid var(--moyako-primary) !important; }
/* ── Game-end overlay (results modal) → wooden. The panel bg is HARDCODED dark
   slate (#3A4258→#1F2433 in moyako-layout.css) — not token-based — so the wooden
   theme never reached it (Owner: "gameend background/design as shared objects not
   applied properly"). Override the panel to the shared parchment surface and pin
   the text espresso/brown (the panel's own light text + the global h1/h2/h3→ivory
   rule would otherwise vanish on parchment). Buttons keep the wooden .btn-* rules. */
[data-theme="wooden"] .page .overlay-content {
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  border: 2px solid #8C6428 !important;
  box-shadow: inset 0 0 0 1px #D2A85A, 0 8px 32px rgba(16,8,3,0.45) !important;
  color: #2A1B12 !important;
  text-shadow: none !important;
}
[data-theme="wooden"] .overlay-content :is(h1,h2,h3),
[data-theme="wooden"] .overlay-title,
[data-theme="wooden"] .overlay-stat-value { color: #2A1B12 !important; text-shadow: none !important; }
[data-theme="wooden"] .overlay-subtitle,
[data-theme="wooden"] .overlay-stat-label,
[data-theme="wooden"] .overlay-pill,
[data-theme="wooden"] .overlay-narrative,
[data-theme="wooden"] .overlay-narrative * { color: #4B3626 !important; text-shadow: none !important; }
[data-theme="wooden"] .overlay-results-card,
[data-theme="wooden"] .overlay-stat,
[data-theme="wooden"] .overlay-pill {
  background: rgba(120,74,28,0.07) !important;
  border-color: #B8893A !important;
}
[data-theme="wooden"] .moyako-card {
  /* real parchment paper texture + soft edge highlight */
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),   /* aged wash — mutes texture banding */
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat;
  background-size: auto, auto, 360px auto;
  color: var(--moyako-text);         /* espresso on parchment */
  border: 1px solid var(--moyako-border);
  border-radius: 16px;
  box-shadow: var(--moyako-shadow-md), inset 0 1px 0 rgba(255,255,255,0.45);
}
[data-theme="wooden"] .moyako-header {
  background: var(--moyako-header-bg);
  border-bottom: 1px solid var(--moyako-border-strong);
  color: var(--moyako-text-light);
}
/* Top brand bar (top-bar.js renders .topbar) — wooden header on EVERY page
   (games-grid/picker, dashboard, leaderboard, assessment, all games). Was
   chess-inline only, so other pages kept the Core header. */
[data-theme="wooden"] header.topbar,
[data-theme="wooden"] .topbar {
  /* Cohesion pass C1 (2026-06-01): warmer, less-black header per design
     review. Direct override (not the --moyako-header-bg token) so the
     bottom nav — which shares that token and already reads well — stays
     untouched. Applies on every wooden page (the topbar is global). */
  background: linear-gradient(180deg, #3A2412 0%, #321F10 100%) !important;
  border-bottom: 1px solid #8A5A22 !important;
  color: var(--moyako-text-light) !important;
}
/* Wooden header action icons → warm gold (sound + settings). */
[data-theme="wooden"] .topbar-sound,
[data-theme="wooden"] .topbar-settings {
  color: #D8A63A !important;
}
/* Header sits on the DARK walnut bar → text must be IVORY. The Step-1 token remap
   set --text-primary to espresso (correct for parchment cards, wrong for the dark
   header), so .topbar-title/.topbar-subtitle went dark-on-dark. Force ivory here —
   the header is a dark surface, not a parchment card. */
[data-theme="wooden"] .topbar-titles,
[data-theme="wooden"] .topbar-title,
[data-theme="wooden"] .topbar-subtitle,
[data-theme="wooden"] .topbar-name { color: var(--moyako-text-light) !important; }
/* Headings: serif (Playfair) everywhere; COLOUR is context-aware. Wooden is
   dark-bg + light-cards, so page-level headings on the walnut bg must be IVORY,
   while headings inside parchment cards (+ the picker title div) are espresso.
   (Previously espresso was global → landing/page headings went invisible on walnut.) */
[data-theme="wooden"] h1,
[data-theme="wooden"] h2,
[data-theme="wooden"] h3,
[data-theme="wooden"] .game-info-title {
  font-family: var(--font-display) !important;   /* Playfair Display (self-hosted) */
}
[data-theme="wooden"] h1,
[data-theme="wooden"] h2,
[data-theme="wooden"] h3 {
  color: var(--moyako-text-light) !important;     /* page-level → ivory on walnut */
}
[data-theme="wooden"] .game-info-title,
[data-theme="wooden"] .moyako-card :is(h1,h2,h3),
[data-theme="wooden"] .game-info-card :is(h1,h2,h3),
[data-theme="wooden"] .moyako-game-card :is(h1,h2,h3),
[data-theme="wooden"] .kpi-card :is(h1,h2,h3),
[data-theme="wooden"] .chart-card :is(h1,h2,h3),
[data-theme="wooden"] .test-card :is(h1,h2,h3),
[data-theme="wooden"] .sudoku-group :is(h1,h2,h3),
[data-theme="wooden"] .auth-welcome-card :is(h1,h2,h3),
[data-theme="wooden"] .auth-welcome-card .welcome-title,
[data-theme="wooden"] .auth-card :is(h1,h2,h3),
[data-theme="wooden"] .settings-panel :is(h1,h2,h3,h4,h5),
[data-theme="wooden"] .settings-title,
[data-theme="wooden"] .login-mask__title,
[data-theme="wooden"] .login-mask__form-title {
  color: var(--moyako-text-strong) !important;    /* on parchment → espresso */
}
/* Sign-in mask headings were near-invisible ivory on the cream card (the global
   h1/h2/h3→ivory rule beat their var(--text-primary)). Espresso above + bold
   here per Owner ("Welcome to Moyako"/"Sign In" should be dark brown, weight 800). */
[data-theme="wooden"] .login-mask__title,
[data-theme="wooden"] .login-mask__form-title { font-weight: 800 !important; }
/* Welcome card was floating (24px padding + 96px logos + 18px gaps → ~363px tall
   banner). Tighten to a focused panel (Owner #2): less padding, smaller hero pair,
   tighter gaps. v526 (2026-06-06) — promoted to THEME-AGNOSTIC per Owner rule
   "themes differ only in colour/font, not sizes/spaces" (DESIGN-RULES §15): all
   themes share these compact sign-in metrics; only colour/texture stays per theme. */
.login-mask__welcome { padding: 12px 20px !important; gap: 8px !important; }
.login-mask__hero-row { gap: 14px !important; }
.login-mask__logo,
.login-mask__panda { width: 74px !important; height: 74px !important; }
/* Header logo height is shared structure → set once on the base rule
   (moyako-components.css .topbar-logo img: 38px), not per theme. */
[data-theme="wooden"] .game-info-subtitle,
[data-theme="wooden"] .game-info-card p,
[data-theme="wooden"] .game-info-skill,
[data-theme="wooden"] .auth-welcome-card p,
[data-theme="wooden"] .auth-welcome-card .welcome-msg,
[data-theme="wooden"] .auth-card p {
  color: var(--moyako-text) !important;
}
/* Page-level intro / lead copy sits on the walnut PAGE (not a parchment card),
   so it needs ivory like the page headings — NOT the espresso used inside cards.
   Card-scoped <p> stays espresso via the rules above. Add other page-header lead
   selectors here as they surface. */
[data-theme="wooden"] .selection-title p,
[data-theme="wooden"] .test-selection .selection-title p {
  color: var(--moyako-text-light) !important;
}
/* Skill emoji → wooden-tinted (sepia/brass) to align with the theme — keep the
   EXISTING emoji (per Owner), just colour-shift them warm. The label text is
   already espresso/brown so the filter's effect on it is negligible. Applies to
   the picker chips + the games-grid skill line. */
[data-theme="wooden"] .game-info-skill,
[data-theme="wooden"] .game-skills {
  filter: sepia(0.6) saturate(1.3) brightness(0.95) hue-rotate(345deg);
}

/* ── Settings modal → SAME textured parchment surface as the picker game-info
   card (Owner: "settings background not aligned to picker game info container").
   The panel already resolves to --bg-surface (flat parchment cream under wooden);
   promote it to the textured parchment + brass so it reads as one set. Text stays
   espresso/brown via the DEFAULT wooden tokens (readable on parchment) — we do NOT
   re-declare tokens here. The Moyako+ wordmark + "+" use a silver/gold gradient
   tuned for the OLD dark sheet (invisible on cream) → re-gradient to espresso +
   brass so the brand mark reads on parchment. ── */
[data-theme="wooden"] .settings-popover .settings-panel {
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  border: 2px solid #8C6428 !important;
  box-shadow: inset 0 0 0 1px #D2A85A, 0 10px 28px rgba(16,8,3,0.45) !important;
}
[data-theme="wooden"] .sm-plus-row__title {
  background: linear-gradient(180deg, #2A1B12 0%, #4B3626 55%, #6F5A45 100%) !important;
  -webkit-background-clip: text !important; background-clip: text !important;
  filter: none !important;
}
[data-theme="wooden"] .sm-plus-row__plus {
  background: linear-gradient(180deg, #8A5E22 0%, #5E4018 100%) !important;
  -webkit-background-clip: text !important; background-clip: text !important;
  filter: drop-shadow(0 0 2px rgba(122,85,34,0.28)) !important;
}
/* Segmented controls in the modal — inactive pill = espresso on tan (the
   --moyako-text-strong token is re-declared light deeper in the tree, so pin it
   explicitly); the selected pill keeps ivory on the felt-green fill. */
[data-theme="wooden"] .settings-panel .seg-btn { color: #2A1B12 !important; }
[data-theme="wooden"] .settings-panel .seg-btn.is-active,
[data-theme="wooden"] .settings-panel .seg-btn[aria-pressed="true"],
[data-theme="wooden"] .settings-panel .seg-btn.is-selected { color: #FFF3D0 !important; }

/* ── Button system (Owner brief): green-felt primary · tan secondary ·
   burgundy danger · burnished-amber CTA. Scoped !important beats the
   hardcoded per-component fills; fires ONLY under [data-theme="wooden"], so
   Dark/Light/Cream are untouched. ── */
[data-theme="wooden"] .btn-primary,
[data-theme="wooden"] .btn-action {
  background: var(--moyako-primary-grad) !important;
  color: #FFF8E8 !important;
  border: 1px solid #8C6428 !important;   /* brass edge (Owner: green felt + brass edge) */
  box-shadow: inset 0 1px 0 rgba(255,247,224,0.28), inset 0 0 0 1px rgba(31,92,52,0.45), 0 4px 10px rgba(16,8,3,0.30) !important;
}
[data-theme="wooden"] .btn-secondary,
[data-theme="wooden"] .btn-return {
  background: linear-gradient(180deg, #F8EAC5 0%, #DFC48D 100%) !important;
  color: var(--moyako-text-strong) !important;
  border: 1px solid #A9792B !important;   /* brass */
  /* premium 3D tile: top highlight + bottom inner shadow + drop (Owner: not flat) */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.50), inset 0 -2px 4px rgba(122,85,34,0.16), 0 2px 6px rgba(16,8,3,0.22) !important;
  opacity: 1 !important;
}
[data-theme="wooden"] .btn-danger,
[data-theme="wooden"] [class*="--danger"] {
  background: linear-gradient(180deg, #A94432 0%, #7F251D 100%) !important;
  color: #FFF8E8 !important;
  border: 1px solid #5F1712 !important;
}
[data-theme="wooden"] .btn-cta,
[data-theme="wooden"] [class*="--rewarded"] {
  background: linear-gradient(180deg, #D9923A 0%, #B85F17 100%) !important;
  color: #FFF8E8 !important;
  border: 1px solid #7A3A0C !important;
}
/* ── Button states (Owner P2: tactile feedback). :active presses in with an
   inset shadow + 1px push-down; :disabled mutes + greys. Covers the whole button
   family + the in-game action buttons. Wooden-scoped. ── */
[data-theme="wooden"] .btn-primary:active,
[data-theme="wooden"] .btn-action:active,
[data-theme="wooden"] .btn-secondary:active,
[data-theme="wooden"] .btn-return:active,
[data-theme="wooden"] .btn-danger:active,
[data-theme="wooden"] .btn-cta:active,
[data-theme="wooden"] .board-lower-action-btn:active {
  transform: translateY(1px) !important;
  box-shadow: inset 0 2px 6px rgba(16,8,3,0.40), inset 0 1px 0 rgba(255,247,224,0.12) !important;
  filter: brightness(0.95) !important;
}
[data-theme="wooden"] .btn-primary:disabled,
[data-theme="wooden"] .btn-action:disabled,
[data-theme="wooden"] .btn-secondary:disabled,
[data-theme="wooden"] .btn-return:disabled,
[data-theme="wooden"] .btn-danger:disabled,
[data-theme="wooden"] .btn-cta:disabled,
[data-theme="wooden"] .board-lower-action-btn:disabled,
[data-theme="wooden"] .board-lower-action-btn[disabled] {
  opacity: 0.45 !important;
  filter: grayscale(0.35) !important;
  cursor: not-allowed !important;
  box-shadow: none !important;
  transform: none !important;
}

/* ── Game numpad + control buttons → wooden (Owner sudoku/maze review). SHARED:
   the .number-pad-numbers panel + .number-btn (sudoku 1-9 · maze d-pad) → dark
   walnut base + parchment buttons. The .control-btn family (sudoku Notes/Erase/
   Check/Hints · block-puzzle controls) → parchment; Check = green felt, Hint =
   amber CTA, Erase = burgundy glyph. High specificity beats the Core metallic
   base; one source, every game. ── */
/* v509 (2026-06-05) — Owner: keypad walnut REMOVED; the keys now sit on the
   light-wooden .board-lower parchment card (rule below), like the picker. */
[data-theme="wooden"] body[data-moyako-v2] .page .number-pad-numbers {
  /* v525 — control KEY container = light-wooden parchment (Owner: "control key
     container light wooden, the one at picker game-info"), nested inside the
     walnut MAIN control container (.board-lower). Shared across all games. */
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  border: 2px solid #8C6428 !important;
  border-radius: 12px !important;
  box-shadow: inset 0 0 0 1px #D2A85A !important;
  padding: 8px !important;
}
/* v509 — control-key container = light-wooden parchment card (picker game-info
   recipe): texture + brass band. Content centred, no overflow/scroll (Owner
   "rule for all"). Shared across every game's .board-lower. */
[data-theme="wooden"] body[data-moyako-v2] .page .board-lower {
  /* v525 — MAIN control container = WALNUT (Owner). The light-wooden key
     container (.number-pad-numbers) nests inside; the walnut frames it. Shared. */
  background: linear-gradient(180deg, #4A2E18 0%, #2A180C 100%) !important;
  border: 2px solid #8C6428 !important;
  border-radius: 12px !important;
  box-shadow: inset 0 0 0 1px #D2A85A, var(--moyako-shadow-md) !important;
  justify-content: center !important;
  overflow: hidden !important;
}
/* v514 — game container = SAME parchment frame as the control container (Owner
   2026-06-05 "make this border standard for all 8 games"). Board sits inside with
   a >=2px inset (padding) so it never touches the frame. Shared .board-upper. */
[data-theme="wooden"] body[data-moyako-v2] .page .board-upper {
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  border: 2px solid #8C6428 !important;
  border-radius: 12px !important;
  box-shadow: inset 0 0 0 1px #D2A85A, var(--moyako-shadow-md) !important;
  padding: 6px !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
}
[data-theme="wooden"] body[data-moyako-v2] .page .number-pad-numbers .number-btn {
  background: linear-gradient(180deg, #F5E8CC 0%, #E5D2AC 100%) !important;
  color: #2A1B12 !important;
  border: 1px solid #B4832D !important;
  text-shadow: none !important;
}
[data-theme="wooden"] body[data-moyako-v2] .page .number-pad-numbers .number-btn:active {
  background: linear-gradient(180deg, #E5D2AC 0%, #D2B98A 100%) !important;
}
[data-theme="wooden"] .control-btn {
  background: linear-gradient(180deg, #F5E8CC 0%, #E5D2AC 100%) !important;
  color: #2A1B12 !important;
  border: 1px solid #B4832D !important;
}
/* v508 (2026-06-05) — Owner: Check + Hint had full green/amber FILLS that broke
   the parchment control row (Notes/Erase/numpad all parchment). Drop the fills so
   they inherit the .control-btn parchment (705); semantic stays in the TEXT only —
   felt-green ✓ for Check, espresso for Hint (its 💡 + count badge carry meaning),
   matching the Erase red-text pattern (718). */
[data-theme="wooden"] .control-btn--check {
  color: #1F5C34 !important;
}
[data-theme="wooden"] .control-btn--hint {
  color: #2A1B12 !important;
}
[data-theme="wooden"] #eraseBtn { color: #8C2A20 !important; }

/* ── Wooden bottom nav: polished wood footer + brass active state. ── */
[data-theme="wooden"] footer.bottom-nav,
[data-theme="wooden"] .bottom-nav {
  background: linear-gradient(180deg, #3A220F 0%, #241307 100%) !important;
  border-top: 1px solid var(--moyako-border-strong) !important;
  box-shadow: 0 -4px 12px rgba(0,0,0,0.32) !important;
}
[data-theme="wooden"] .bottom-nav a,
[data-theme="wooden"] .bottom-nav button {
  color: #D6BE8A !important;            /* inactive — readable warm tan (Owner) */
  font-weight: 500 !important;
}
[data-theme="wooden"] .bottom-nav .nav-item:not(.is-active) .nav-icon { opacity: 0.82 !important; }
/* Active marker is .is-active (bottom-nav.js), NOT .active. The [data-moyako-v2]
   qualifier lifts this to (0,5,0) to beat Core's orange .nav-item.is-active
   (#F97316) — there's a per-theme override for light/cream but none for wooden. */
[data-theme="wooden"] [data-moyako-v2] .bottom-nav .nav-item.is-active,
[data-theme="wooden"] .bottom-nav .nav-item.is-active {
  color: #F1C46B !important;            /* bright brass — pops, replaces Core orange (Owner) */
  font-weight: 700 !important;
  background: rgba(210,168,90,0.20) !important;
  box-shadow: inset 0 2px 0 0 var(--moyako-primary-light) !important;   /* brass top indicator */
}
[data-theme="wooden"] .bottom-nav .nav-item.is-active .nav-icon { opacity: 1 !important; filter: brightness(1.08) !important; }
/* v2 ringless brass icons (Owner pack v2) — no medallion coins, per the v2 brief */
[data-theme="wooden"] .bottom-nav .nav-icon {
  font-size: 0 !important;
  width: 30px !important; height: 30px !important;
  display: inline-block !important;
  background-repeat: no-repeat !important;
  background-position: center !important;
  background-size: contain !important;
}
[data-theme="wooden"] .nav-item[href*="dashboard"]  .nav-icon { background-image: url("assets/wooden/premium/shell/home_wooden.svg") !important; }
[data-theme="wooden"] .nav-item[href*="games"]       .nav-icon { background-image: url("assets/wooden/premium/shell/games_wooden.svg") !important; }
[data-theme="wooden"] .nav-item[href*="assessment"]  .nav-icon { background-image: url("assets/wooden/premium/shell/test_wooden.svg") !important; }
[data-theme="wooden"] .nav-item[href*="leaderboard"] .nav-icon { background-image: url("assets/wooden/premium/shell/leaderboard_wooden.svg") !important; }

/* Top-bar shell chrome → v2 ringless brass icons (Owner pack v2).
   top-bar.js paints line-art <svg.moyako-icon> inline; hide it and use the
   v2 icon as the button face. Sound state lives in aria-pressed (no class).
   Hooked on [data-action] so the landscape-migrated clones theme too.
   Scope is effectively chess-only — Wooden is flavor-gated to chess. */
[data-theme="wooden"] [data-action="sound"],
[data-theme="wooden"] [data-action="settings"] {
  width: 34px !important; height: 34px !important;
  min-height: 0 !important; padding: 0 !important;
  background: transparent center / contain no-repeat !important;
  border: 0 !important; box-shadow: none !important;
}
[data-theme="wooden"] [data-action="sound"] .moyako-icon,
[data-theme="wooden"] [data-action="settings"] .moyako-icon { display: none !important; }
[data-theme="wooden"] [data-action="settings"] {
  background-image: url("assets/wooden/premium/shell/settings_wooden.svg") !important;
}
/* sound on = default (covers aria-pressed="true" and the pre-JS unset state) */
[data-theme="wooden"] [data-action="sound"]:not([aria-pressed="false"]) {
  background-image: url("assets/wooden/premium/shell/sound_on_wooden.svg") !important;
}
/* sound off — premium pack ships a real mute icon */
[data-theme="wooden"] [data-action="sound"][aria-pressed="false"] {
  background-image: url("assets/wooden/premium/shell/sound_off_wooden.svg") !important;
}

/* Skill chips: KEEP THE EMOJI. Earlier I replaced them with brass icons keyed by
   nth-child — but that was chess-specific (planning/pattern/spatial), so once
   wooden cascaded to all games it showed the WRONG icon per position (sudoku's
   "Logic" got the planning target, etc.). Removed. The emoji is the correct,
   generic per-skill indicator and matches the games-grid skill line, so both the
   picker chips and the games screen now show emoji consistently. (A premium
   per-skill brass set could return later keyed by a data-skill attribute on the
   chip — both render paths — if we want it.) */

/* ── Wooden game-picker heroes → branded wooden logos (game_logos pack, downscaled
   to 360px). Keyed by .game-icon--<gameId> from picker-pane — rolls the chess MC_W
   treatment to all 7 games (hybrid Phase 1). Box sizing left to each game's existing
   hero layout; square logos fit via contain. Chess also has an inline rule in
   chess.html (same MC_W image) — harmless redundancy. ── */
[data-theme="wooden"] .game-info-icon {
  border: 0 !important; border-radius: 0 !important; box-shadow: none !important;
  background-position: center !important; background-repeat: no-repeat !important;
  background-size: contain !important;
}
[data-theme="wooden"] .game-info-icon::before { content: none !important; }
[data-theme="wooden"] .game-icon--chess        { background-image: url("assets/wooden/premium/game_logos/MC_W.png") !important; }
[data-theme="wooden"] .game-icon--sudoku       { background-image: url("assets/wooden/premium/game_logos/MS_W.png") !important; }
[data-theme="wooden"] .game-icon--memory       { background-image: url("assets/wooden/premium/game_logos/MMM_W.png") !important; }
[data-theme="wooden"] .game-icon--backgammon   { background-image: url("assets/wooden/premium/game_logos/MBG_W.png") !important; }
[data-theme="wooden"] .game-icon--block-puzzle { background-image: url("assets/wooden/premium/game_logos/MBP_W.png") !important; }
[data-theme="wooden"] .game-icon--word-puzzle  { background-image: url("assets/wooden/premium/game_logos/MWP_W.png") !important; }
[data-theme="wooden"] .game-icon--maze         { background-image: url("assets/wooden/premium/game_logos/MM_W.png") !important; }

/* ═══ Wooden gameplay HUD + surfaces + difficulty — PROMOTED from the chess pilot
   to shared (Phase 2a). These target classes ALL 6 games share (.sudoku-group,
   .number-pad*, .board-lower-*, .moyako-difficulty-btn, .cap-nav), so the de-blue
   HUD + parchment surfaces + felt difficulty + wooden buttons cascade platform-wide.
   chess.html inline parchment/frame copies removed 2026-05-26 — this sheet is the
   single source for card surfaces (HUD/board inline rules still live in chess.html).
   Per-game UNIQUE boards (sudoku grid, maze walls, …) remain Phase 2b. ═══ */
/* Content surfaces → parchment. ONE shared wooden card surface — every panel
   card (picker, welcome/auth, gameplay, history) shares the SAME parchment fill
   + brass double-line, so the whole platform reads as one set. The picker hero
   pair adds the ornate carved frame on top (rule directly below). */
[data-theme="wooden"] .sudoku-group,
[data-theme="wooden"] .game-board-container,
[data-theme="wooden"] .game-info-card,
[data-theme="wooden"] .game-info-skill,
[data-theme="wooden"] .difficulty-card,
[data-theme="wooden"] .moyako-move-list,
[data-theme="wooden"] .auth-card,
[data-theme="wooden"] .auth-welcome-card,
/* v502 (2026-06-05) — Owner: align sign-in + game-end containers to the
   picker's wooden surface (background + border). Sign-in mask
   (.login-mask__welcome / __form, dashboard.html) and game-end cards
   (.results-card) join the parchment base here and the carved frame below. */
[data-theme="wooden"] .login-mask__welcome,
[data-theme="wooden"] .login-mask__form,
[data-theme="wooden"] .results-card {
  background:
    linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
    radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, auto, 360px auto !important;
  color: var(--moyako-text) !important;
  border: 2px solid #8C6428 !important;
  box-shadow: inset 0 0 0 1px #D2A85A, var(--moyako-shadow-md) !important;
}
/* Picker hero pair → ornate brass+wood carved frame (border-image places the
   4 corners crisply at any aspect ratio). Both panes match as a set. Moved here
   from the chess.html inline copy so every future deep-skinned game inherits it.
   v502 (2026-06-05) — Owner extended the carved frame to the sign-in mask
   (.login-mask__welcome / __form) + game-end cards (.results-card) so all three
   two-container screens read as one set (was picker-only). Other dashboard
   tiles still keep the plainer brass band above. */
[data-theme="wooden"] .game-info-card,
[data-theme="wooden"] .difficulty-card,
[data-theme="wooden"] .login-mask__welcome,
[data-theme="wooden"] .login-mask__form {
  /* v517 (2026-06-05) — .results-card REMOVED from this carved-frame group: the
     14px border-image frame (×2 dense result cards) overflowed the cap-shell
     height, cropping the Score/TOP-5 row + spilling the buttons. Results cards
     keep the plainer parchment + brass-band surface (group above ~:873). The
     carved frame stays on the content-light picker hero + sign-in mask only. */
  border: 14px solid transparent !important;
  border-image: url("assets/wooden/svg/material/theme_classic_frame_panel.svg") 44 / 14px / 0 stretch !important;
  border-radius: 18px !important;
  box-shadow: var(--moyako-shadow-md) !important;
}
/* Difficulty tiles — inactive tan; selected felt-green + brass border + brass ring + check */
[data-theme="wooden"] .moyako-difficulty-btn,
[data-theme="wooden"] .seg-btn {
  background: linear-gradient(180deg, #F6E7C3 0%, #DFC48D 100%) !important;
  color: var(--moyako-text-strong) !important;
  border: 1px solid var(--moyako-border-strong) !important;
}

/* Settings-modal polish. */
/* (1) Account action buttons (Download / Send / Delete / Manage / Buy / View
   plans) → Title Case in ALL themes, not UPPERCASE. The global `button {}` rule
   (styles.css) uppercases every <button>, so these read "DOWNLOAD"; the i18n
   labels are already Title Case. UN-SCOPED from wooden (Owner 2026-05-27: "align
   all fields for all themes" + "why is the download button wider on the other
   templates" — "DOWNLOAD" renders ~10px wider than "Download", so wooden looked
   narrower). Now consistent Title Case + width across Dark/Light/Wooden. The
   parchment COLORS below stay wooden-scoped (color differs per theme). */
.sm-account-btn { text-transform: none !important; }
/* (1b) Account action buttons (Download / Send / Delete / Manage / Buy / View
   plans) → wooden parchment fill + brass border. The Core faint-white pill +
   green/red outline never got a wooden skin (Owner: "align the download, send,
   delete buttons as in wooden ... they are shared objects" + "align all fields
   for all themes, only coloring different"). Action text keeps a wooden-toned
   hue so the affordance survives: felt-green for neutral, burgundy for danger. */
[data-theme="wooden"] .sm-account-btn {
  background: linear-gradient(180deg, #F6E7C3 0%, #DFC48D 100%) !important;
  border: 1px solid var(--moyako-border-strong) !important;
  color: #2F7D46 !important;                 /* felt-green action text — AA on parchment */
  box-shadow: inset 0 1px 0 rgba(255,247,224,0.45), 0 1px 3px rgba(16,8,3,0.18) !important;
}
[data-theme="wooden"] .sm-account-btn:hover {
  background: linear-gradient(180deg, #F9ECC9 0%, #E3CB95 100%) !important;
}
[data-theme="wooden"] .sm-account-btn.is-danger {
  border-color: #9B2F24 !important;
  color: #9B2F24 !important;                 /* burgundy danger — AA on parchment */
}
[data-theme="wooden"] .sm-account-btn.is-danger:hover {
  background: linear-gradient(180deg, #F4E1D6 0%, #E6C4B2 100%) !important;
}
/* (2) Toggle switch → wooden palette: ON = green felt, OFF = warm-brown track
   (the base was Core orange #FF6B35 on / faint-white off, not theme-aligned).
   White knob kept for contrast on both states. */
[data-theme="wooden"] .sm-toggle { background: rgba(122, 85, 34, 0.38) !important; }
[data-theme="wooden"] .sm-toggle.is-on {
  background: linear-gradient(180deg, #3D9A55 0%, #2F7D46 100%) !important;
}
/* (3) Background / Language / Sound selector rows are tall because the global
   solid-3D <select> padding (12px) inflates them; trim it inside the settings
   modal so the rows read more compact. */
/* v526 — compact select rows are shared structure (Owner §15): all themes share
   the 8px vertical padding; only colour/texture stays per theme. */
.sm-toggle-row select {
  padding-top: 8px !important;
  padding-bottom: 8px !important;
}
[data-theme="wooden"] .moyako-difficulty-btn.is-selected,
[data-theme="wooden"] .moyako-difficulty-btn.active,
[data-theme="wooden"] .moyako-difficulty-btn[aria-pressed="true"],
[data-theme="wooden"] .seg-btn.is-active,
[data-theme="wooden"] .difficulty-card.active {
  background: linear-gradient(180deg, #2F7D46 0%, #1E5631 100%) !important;
  color: var(--moyako-text-light) !important;
  border: 2px solid var(--moyako-border-light) !important;
  box-shadow: 0 0 0 2px rgba(210,168,90,0.55), inset 0 1px 0 rgba(255,247,224,0.20), 0 2px 7px rgba(16,8,3,0.32) !important;
}
[data-theme="wooden"] .moyako-difficulty-btn.is-selected .difficulty-label,
[data-theme="wooden"] .moyako-difficulty-btn.active .difficulty-label,
[data-theme="wooden"] .moyako-difficulty-btn[aria-pressed="true"] .difficulty-label { color: var(--moyako-text-light) !important; }
[data-theme="wooden"] .moyako-difficulty-btn.is-selected::after,
[data-theme="wooden"] .moyako-difficulty-btn.active::after,
[data-theme="wooden"] .moyako-difficulty-btn[aria-pressed="true"]::after { color: #EBC974 !important; }

/* Difficulty SELECTED tile (wooden) — Owner: do NOT fill it green. Keep the
   parchment tile (like unselected), carry the tier's DOT colour into the
   border + ✓ tick at the SAME 1px weight. Overrides both the wooden green-felt
   block above and the shared v451 green selection ring (moyako-layout.css).
   The tier colour rides on `color` so border:currentColor + the ✓ inherit it;
   label/emoji are forced espresso so they stay readable on parchment. The base
   per-tier dot colours (#A5D6A7 / #81C784 / #FFB74D / #EF5350 / #9C27B0 /
   #29B6F6) are re-used verbatim. Other themes keep the v451 green ring. */
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"]) {
  background: linear-gradient(180deg, #F6E7C3 0%, #DFC48D 100%) !important;
  border: 1px solid currentColor !important;
  box-shadow: inset 0 1px 0 rgba(255, 247, 224, 0.40), 0 2px 5px rgba(16, 8, 3, 0.18) !important;
}
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])[data-tier="beginner"] { color: #A5D6A7 !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])[data-tier="easy"]     { color: #81C784 !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])[data-tier="medium"]   { color: #FFB74D !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])[data-tier="hard"]     { color: #EF5350 !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])[data-tier="expert"]   { color: #9C27B0 !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])[data-tier="auto"]     { color: #29B6F6 !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"])::after { color: currentColor !important; }
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"]) .difficulty-label,
[data-theme="wooden"] [data-moyako-v2] .page .difficulty-card .difficulty:is(.is-selected, .active, [aria-pressed="true"]) .difficulty-emoji { color: #2A1B12 !important; }
/* De-blue HUD containers → transparent */
[data-theme="wooden"] .number-pad-info,
[data-theme="wooden"] .number-pad,
[data-theme="wooden"] .number-pad--triple,
[data-theme="wooden"] .board-lower-history-head { background: transparent !important; background-image: none !important; }
/* v528 (2026-06-08) — landscape control container aligned to portrait (Owner: "control
   container background and border style not aligned to portrait").

   The shared landscape control-column backdrop is the .moyako-board-center::before grid
   item (moyako-layout.css §988 — spans col 2 / all control rows, themed there per theme).
   v574 painted its WOODEN variant CREAM (#F5E8CC); but portrait's container (.board-lower,
   v525) is WALNUT, so landscape didn't match. The backdrop is now WALNUT + 2px brass in
   moyako-layout.css §1018 (matching portrait .board-lower). Here we only keep the control
   LEAVES transparent so that single walnut backdrop reads as ONE container — the old
   per-leaf walnut (v515/v525) made them separate bordered tiles. The keypad keeps its
   light-wooden parchment card → portrait's walnut-container + parchment-keys island, now
   in landscape too. Scoped to phone landscape (max-width:1024). Shared, all games. */
@media (orientation: landscape) and (max-width: 1024px) {
  [data-theme="wooden"] body[data-moyako-v2] .page .moyako-board-center .number-pad-info,
  [data-theme="wooden"] body[data-moyako-v2] .page .moyako-board-center .board-lower-actions,
  [data-theme="wooden"] body[data-moyako-v2] .page .moyako-board-center .board-lower-history {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
  }
}
/* Keypad = light-wooden parchment card sitting on the walnut backdrop (matches portrait).
   v531 — memory's category container (.number-pad-keys) joins the SAME parchment card so
   it reads like sudoku's numpad (Owner: "align to sudoku — control key container lighter
   wooden, buttons centred within"). */
@media (orientation: landscape) {
  [data-theme="wooden"] body[data-moyako-v2] .page .moyako-board-center .number-pad-numbers,
  [data-theme="wooden"] body[data-page-brand-label="Memory Game"][data-moyako-v2] .page .moyako-board-center .number-pad-keys {
    background:
      linear-gradient(rgba(247,235,207,0.52), rgba(247,235,207,0.52)),
      radial-gradient(circle at 28% 0%, rgba(255,250,235,0.14), transparent 60%),
      url("assets/wooden/parchment.png") repeat !important;
    background-size: auto, auto, 360px auto !important;
    border: 2px solid #8C6428 !important;
    border-radius: 12px !important;
    box-shadow: inset 0 0 0 1px #D2A85A !important;
    /* v532 — keys card reads as a SECONDARY element nested inside the walnut control
       container: 2px breathing space on every side to the walnut frame (Owner). */
    margin: 2px !important;
  }
}
/* Match-up panel → dark leather */
[data-theme="wooden"] .number-pad-info .board-lower-matchup,
[data-theme="wooden"] .board-lower-matchup {
  background:
    radial-gradient(circle at 50% 0%, rgba(120,74,28,0.22), transparent 65%),
    linear-gradient(180deg, #4A2B13 0%, #2E1A0C 100%) !important;
  color: var(--moyako-text-light) !important;
  border: 1px solid var(--moyako-border-strong) !important;
  box-shadow: inset 0 1px 0 rgba(210,168,90,0.20) !important;
}
[data-theme="wooden"] .matchup-vs { color: var(--moyako-text-light-muted) !important; }
/* Stat tiles → parchment + warm values + brass icons */
[data-theme="wooden"] .board-lower-stat {
  background: var(--moyako-card-grad) !important;
  color: var(--moyako-text) !important;
  border: 1px solid var(--moyako-border) !important;
}
[data-theme="wooden"] .board-lower-stat-value { color: var(--moyako-text-strong) !important; }
[data-theme="wooden"] .board-lower-stat-label { color: var(--moyako-text-muted) !important; }
[data-theme="wooden"] .board-lower-stat[data-stat="time"] .board-lower-stat-value { color: #315A78 !important; }
[data-theme="wooden"] .board-lower-stat[data-quality="good"] .board-lower-stat-value,
[data-theme="wooden"] .board-lower-stat[data-stat="score"] .board-lower-stat-value { color: #1F5C34 !important; }
[data-theme="wooden"] .board-lower-stat[data-quality="bad"] .board-lower-stat-value,
[data-theme="wooden"] .board-lower-stat[data-stat="errors"] .board-lower-stat-value { color: #9B2F24 !important; }
[data-theme="wooden"] .board-lower-stat[data-stat="level"] .board-lower-stat-value { color: #7A5522 !important; }
[data-theme="wooden"] .board-lower-stat::before {
  content: ""; display: block; width: 18px; height: 18px; margin: 0 auto 1px;
  background-repeat: no-repeat; background-position: center; background-size: contain;
}
[data-theme="wooden"] .board-lower-stat[data-stat="time"]::before   { background-image: url("assets/wooden/premium/stat/time_wooden.svg"); }
[data-theme="wooden"] .board-lower-stat[data-stat="errors"]::before { background-image: url("assets/wooden/premium/stat/moves_wooden.svg"); }
[data-theme="wooden"] .board-lower-stat[data-stat="score"]::before  { background-image: url("assets/wooden/premium/stat/score_wooden.svg"); }
[data-theme="wooden"] .board-lower-stat[data-stat="level"]::before  { background-image: url("assets/wooden/premium/stat/level_wooden.svg"); }
/* History-head text on walnut */
[data-theme="wooden"] .board-lower-history-head,
[data-theme="wooden"] .board-lower-history-head * { color: var(--moyako-text-light-muted) !important; }
/* In-game action buttons: tan / burgundy danger / amber rewarded+primary */
[data-theme="wooden"] .board-lower-action-btn {
  background: linear-gradient(180deg, #F6E7C3 0%, #DFC48D 100%) !important;
  color: var(--moyako-text-strong) !important;
  border: 1px solid var(--moyako-border-strong) !important;
}
/* Resign/danger — fill ALIGNS with the other action buttons (tan), danger
   accent in the TEXT only (burgundy, AA on parchment), per the v459 decision
   (same pattern as --rewarded below). Owner 2026-06-05: resign bg was the
   lone burgundy fill standing out from the parchment action row. */
[data-theme="wooden"] .board-lower-action-btn--danger {
  background: linear-gradient(180deg, #F6E7C3 0%, #DFC48D 100%) !important;
  color: #9B2F24 !important; border: 1px solid var(--moyako-border-strong) !important;
}
/* New Game / primary → amber wood CTA. */
[data-theme="wooden"] .board-lower-action-btn--primary {
  background: linear-gradient(180deg, #D9923A 0%, #B85F17 100%) !important;
  color: #FFF8E8 !important; border: 1px solid #7A3A0C !important;
}
/* Rewarded "Skip" — fill ALIGNS with the other action buttons (tan), reward
   accent in the TEXT only (amber), per the v459 decision. (Was wrongly lumped
   with --primary's amber fill, making Skip stand out orange.) Covers the word-
   puzzle .board-lower-action-btn--rewarded + the maze .control-btn--skip. */
[data-theme="wooden"] .board-lower-action-btn--rewarded {
  background: linear-gradient(180deg, #F6E7C3 0%, #DFC48D 100%) !important;
  color: #B85F17 !important;
  border: 1px solid var(--moyako-border-strong) !important;
}
[data-theme="wooden"] .control-btn--skip { color: #B85F17 !important; }
/* Cap-flavor bottom nav */
[data-theme="wooden"] .cap-nav {
  background: var(--moyako-header-bg) !important;
  border-top: 1px solid var(--moyako-border-strong) !important;
}

/* ===== RESET ===== */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* ===== BASE TYPOGRAPHY =====
 * NOTE: height must be `min-height: 100%` not `height: 100%` — on iOS
 * Safari, capping body to 100% of viewport clips content taller than the
 * window and can make the page feel "not scrollable" when the address
 * bar shows/hides (viewport shrinks). min-height keeps the fill-the-
 * screen behaviour for short pages while letting tall content grow.
 */
html, body {
  width: 100%;
  min-height: 100%;
  background: var(--moyako-metallic);
  color: var(--moyako-text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Title Case rule (DESIGN-RULES §3.16, 2026-05-08): titles use
 * sentence case / Title Case — only initial letters capital, never
 * shouting UPPERCASE. text-transform: uppercase removed from h1/h2/h3
 * globals. Per-element uppercase (badges, labels, micro-copy where
 * uppercase reads as a design treatment, not a title) is still OK. */
h1 {
  font-family: var(--font-display);
  font-size: 1.75rem;
  font-weight: 900;
  line-height: 1.2;
  color: var(--moyako-primary);
  letter-spacing: 0.5px;
  margin-bottom: 1rem;
}

h2 {
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 900;
  line-height: 1.3;
  color: var(--moyako-primary);
  letter-spacing: 0.5px;
  margin-bottom: 1rem;
}

h3 {
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 900;
  color: var(--moyako-primary);
  letter-spacing: 0.25px;
  margin-bottom: 0.75rem;
}

p {
  font-size: 1rem;
  line-height: 1.5;
  color: var(--moyako-text);
  margin-bottom: 1rem;
}

/* ===== HEADER / NAVIGATION ===== */
.moyako-header {
  background: linear-gradient(180deg, var(--moyako-card) 0%, var(--moyako-bg-light) 100%);
  border-bottom: 2px solid var(--moyako-primary);
  padding: var(--spacing-md) var(--spacing-lg);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  box-shadow: var(--moyako-shadow-sm);
}

.moyako-header .moyako-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.moyako-logo {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 900;
  color: var(--moyako-primary);
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 2px;
}

.moyako-logo-icon {
  width: 50px;
  height: 50px;
  background: var(--moyako-primary-grad);
  border-radius: var(--radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3);
}

/* ===== BUTTONS ===== */
/* (Removed 2026-06-08, #520) The orphan .moyako-btn* system (base / primary /
   secondary / play / large) matched ZERO elements — the shared .btn /
   .btn-primary / .btn-secondary system is the single source of truth per
   DESIGN-RULES §3.30. Dead CSS removed; --moyako-primary-grad token is kept
   (still used by other rules). */

/* ===== CARDS ===== */
.moyako-card {
  background: var(--moyako-card);
  border: 1px solid var(--moyako-border-light);
  border-radius: var(--radius-lg);
  padding: var(--spacing-lg);
  box-shadow: var(--moyako-shadow-sm);
  transition: all 0.3s ease;
}

.moyako-card:hover {
  box-shadow: var(--moyako-shadow-md);
  transform: translateY(-2px);
}

/* ===== BADGES ===== */
.moyako-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.375rem 0.75rem;
  background: var(--moyako-primary);
  color: white;
  border-radius: 12px;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  white-space: nowrap;
}

.moyako-badge-accent {
  background: var(--moyako-accent);
}

.moyako-badge-success {
  background: var(--moyako-success);
}

.moyako-badge-error {
  background: var(--moyako-error);
}

/* ===== CONTAINERS & LAYOUT ===== */
.moyako-container {
  max-width: 480px;
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--spacing-md);
}

.moyako-container-lg {
  max-width: 1200px;
}

/* ===== UTILITY CLASSES ===== */
.moyako-text-center {
  text-align: center;
}

.moyako-text-muted {
  color: var(--moyako-text-muted);
}

.moyako-text-error {
  color: var(--moyako-error);
}

.moyako-text-success {
  color: var(--moyako-success);
}

.moyako-mt-sm { margin-top: var(--spacing-sm); }
.moyako-mt-md { margin-top: var(--spacing-md); }
.moyako-mt-lg { margin-top: var(--spacing-lg); }

.moyako-mb-sm { margin-bottom: var(--spacing-sm); }
.moyako-mb-md { margin-bottom: var(--spacing-md); }
.moyako-mb-lg { margin-bottom: var(--spacing-lg); }

.moyako-gap-sm { gap: var(--spacing-sm); }
.moyako-gap-md { gap: var(--spacing-md); }
.moyako-gap-lg { gap: var(--spacing-lg); }

/* ===== ANIMATIONS ===== */
@keyframes moyako-fade-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.moyako-fade-in {
  animation: moyako-fade-in 0.3s ease forwards;
}

@keyframes moyako-pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

.moyako-pulse {
  animation: moyako-pulse 2s ease-in-out infinite;
}

/* ===== ACCESSIBILITY ===== */
/* Minimum 44x44px tap targets for mobile */
button, a[role="button"], input[type="button"], input[type="submit"] {
  min-width: 44px;
  min-height: 44px;
}

/* Focus visible for keyboard navigation */
:focus-visible {
  outline: 3px solid var(--moyako-primary);
  outline-offset: 2px;
}

/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ===== RESPONSIVE BREAKPOINTS ===== */
/* Mobile-first approach: styles default to mobile */
/* Tablet: min-width 640px */
@media (min-width: 640px) {
  :root {
    font-size: 16px;
  }

  .moyako-container {
    max-width: 620px;
  }

  h1 {
    font-size: 2rem;
  }

  h2 {
    font-size: 1.5rem;
  }
}

/* Desktop: min-width 1024px */
@media (min-width: 1024px) {
  .moyako-container {
    max-width: 960px;
  }

  .moyako-container-lg {
    max-width: 1200px;
  }

  h1 {
    font-size: 2.25rem;
  }

  h2 {
    font-size: 1.75rem;
  }
}

/* Large Desktop: min-width 1280px */
@media (min-width: 1280px) {
  .moyako-container-lg {
    max-width: 1280px;
  }
}

/* ===== PRINT STYLES ===== */
@media print {
  .moyako-header,
  .btn,
  [role="navigation"] {
    display: none;
  }
}

/* ===== THEME SWITCHER UTILITY ===== */
.moyako-theme-toggle {
  position: fixed;
  bottom: 80px;
  right: 16px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: var(--moyako-primary);
  color: white;
  font-size: 20px;
  cursor: pointer;
  z-index: 1000;
  box-shadow: var(--moyako-shadow-md);
  transition: transform 0.2s;
}

.moyako-theme-toggle:hover {
  transform: scale(1.1);
}

/* ============================================================
   Moyako Shared Difficulty Picker (used by chess, sudoku, etc.)
   Color-coded tiles with emoji + technique/tier label. Works in
   light and dark themes because the white text is always on a
   gradient background — no CSS-variable inheritance required.
   First shipped for Sudoku 2026-04-12; align all games to this.
   ============================================================ */

/* Single-column stack — 5 tier tiles reading top-to-bottom. Previously
   2-col with an orphaned 5th tile at the bottom. Single-column keeps the
   visual hierarchy (Beginner → Expert) obvious and scrolls cleanly on
   short screens. Gap tightened 10→8 px to match the compact single-line
   tile (name-only, no descriptions). */
.moyako-difficulty-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin-bottom: 20px;
}

.moyako-difficulty-btn {
  padding: 10px 14px;
  min-height: 44px;
  border: 0;
  border-radius: 10px;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.2s ease;
  text-align: center;
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  box-shadow: 0 3px 10px rgba(0,0,0,0.22);
  -webkit-tap-highlight-color: rgba(255,255,255,0.3);
  touch-action: manipulation;
  position: relative;
  overflow: hidden;
  width: 100%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}
.moyako-difficulty-btn:active { transform: scale(0.97); }
.moyako-difficulty-btn:hover  { box-shadow: 0 6px 18px rgba(0,0,0,0.35); }

/* v449 (2026-05-20): legacy per-tier full-bleed gradient backgrounds
 * removed. They predated the dot-indicator + neutral-pill picker
 * design and were rendering loud cyan/green/orange/red/purple fills
 * on backgammon (load-order quirk: backgammon imports styles.css
 * AFTER moyako-components.css, so the legacy gradients won the
 * cascade tie against `[data-moyako-v2] .difficulty { background:
 * var(--bg-surface) }`). Other games load styles.css first, so they
 * never showed the gradients. With the legacy rules gone, every
 * game inherits the same neutral-pill look + tier-coloured dot
 * inside + (when selected) tier-coloured 1px border + tier-coloured
 * ✓ checkmark — single visual language across the suite. */

/* v449 (2026-05-20): legacy `.moyako-difficulty-btn.active` ring rule
 * removed. It drew a 3 px white outer ring + -5 px inset white
 * outline + 1.02 scale-up, which sat on top of the new tier-coloured
 * border (per `.difficulty.is-selected[data-tier="..."]` in
 * moyako-components.css §924) and reintroduced the "extra ring" the
 * user explicitly asked to remove. Legacy games (maze, sudoku) still
 * add the `.active` class via their per-game handlers — that's fine,
 * picker-pane.js's shared capture handler also adds `.is-selected`,
 * and the new rule colours the existing 1 px border via that
 * selector. The ✓ checkmark is now rendered via the `.is-selected`
 * pseudo-element (also in moyako-components.css §1407), tinted to the
 * tier hue. No replacement needed. */

/* Two-section difficulty modal — two symmetric containers stacked:
     .moyako-intro-section   (top    ≈ 50 %)  — icon · title · skills · tier pill
     .moyako-actions-section (bottom ≈ 50 %)  — pills (col 1) · actions (col 2)
   Both sections share visual treatment (background, border, padding)
   so they read as equal siblings rather than "chrome + loose buttons".

   Legacy structure (icon, title, subtitle, grid, button as flat direct
   children — pre-.moyako-intro-section) still works: first three spans
   both cols, grid takes row 2 col 1, trailing button takes row 2 col 2. */
.moyako-difficulty-modal {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 10px;
  max-width: 440px;
  width: min(440px, calc(100vw - 24px));
  height: min(560px, calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 24px));
  max-height: calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 24px);
  overflow: hidden;
  box-sizing: border-box;
}
/* Legacy fallback — modal without explicit sections switches back to
   2-col / 2-row (icon/title/subtitle in row 1, pills+buttons in row 2). */
.moyako-difficulty-modal:not(:has(.moyako-intro-section)):not(:has(.moyako-actions-section)) {
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  grid-template-rows: minmax(auto, 1fr) minmax(auto, 1fr);
  gap: 8px 12px;
  height: auto;
}
.moyako-difficulty-modal > .moyako-intro-section,
.moyako-difficulty-modal > .moyako-actions-section {
  min-height: 0;
  overflow: hidden;
}
/* Intro section spans both cols on row 1 and stacks its own children
   (icon, title, skills, tier) vertically centered. */
.moyako-difficulty-modal > .moyako-intro-section {
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 8px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.06);
  border-radius: 12px;
}
/* Actions section sits in row 2 (below intro). Width spans the full
   modal. Internal 2-col grid is handled by .moyako-actions-section rules. */
.moyako-difficulty-modal > .moyako-actions-section {
  grid-row: 2;
}
.moyako-intro-icon { font-size: 44px; line-height: 1; }
.moyako-intro-title {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: 1px;
  color: #ECEFF4;
  text-align: center;
}
.moyako-intro-skills { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.moyako-intro-skill {
  font-size: 11px;
  font-weight: 600;
  color: #ECEFF4;
  background: rgba(0,0,0,0.25);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
}
.moyako-intro-tier {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 1px;
  color: #fff;
  background: linear-gradient(135deg, #FF9800 0%, #E65100 100%);
  border-radius: 999px;
  padding: 6px 16px;
  text-transform: uppercase;
}
.moyako-intro-tier[data-tier="beginner"] { background: linear-gradient(135deg, #4DD0E1 0%, #0097A7 100%); }
.moyako-intro-tier[data-tier="easy"]     { background: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%); }
.moyako-intro-tier[data-tier="medium"]   { background: linear-gradient(135deg, #FF9800 0%, #E65100 100%); }
.moyako-intro-tier[data-tier="hard"]     { background: linear-gradient(135deg, #E53935 0%, #B71C1C 100%); }
.moyako-intro-tier[data-tier="expert"]   { background: linear-gradient(135deg, #9C27B0 0%, #4A148C 100%); }
/* Actions section — mirrors the intro section visually (same bg, border,
   padding). Internally a 2-col grid: pills left, action buttons right.
   Both columns share the SAME total height (stretch to row), and the
   items inside each column share that height evenly via grid-auto-rows
   so 5 pills and 2–3 action buttons end up with equal-height tiles. */
.moyako-actions-section {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  grid-template-rows: 1fr;
  gap: 8px 10px;
  padding: 10px 12px;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.06);
  border-radius: 12px;
  align-items: stretch;
  overflow: hidden;
}
.moyako-actions-section > .moyako-difficulty-grid {
  grid-column: 1;
  grid-row: 1;
  margin-bottom: 0;
  align-self: stretch;
  height: 100%;
  display: grid;
  grid-auto-rows: 1fr;   /* 5 pills split the column height evenly */
  gap: 8px;
  min-height: 0;
}
.moyako-actions-section > button,
.moyako-actions-section > .overlay-buttons {
  grid-column: 2;
  grid-row: 1;
  align-self: stretch;
  margin-top: 0 !important;
  height: 100%;
  min-height: 0;
}
.moyako-actions-section > .overlay-buttons {
  display: grid;
  grid-auto-rows: 1fr;   /* 1-3 action buttons split the column evenly */
  gap: 8px;
  height: 100%;
}
/* Pills + action buttons inside actions-section share a tight preset
   (min-height:0, padding trimmed, uppercase labels) so they scale down
   cleanly as the grid-auto-rows:1fr redistributes vertical space. */
.moyako-actions-section .moyako-difficulty-btn {
  min-height: 0 !important;
  padding: 4px 10px !important;
  font-size: 13px !important;
  line-height: 1.15;
}
[data-theme="light"] .moyako-actions-section {
  background: rgba(0,0,0,0.03);
  border-color: rgba(0,0,0,0.08);
}

[data-theme="light"] .moyako-difficulty-modal > .moyako-intro-section {
  background: rgba(0,0,0,0.03);
  border-color: rgba(0,0,0,0.08);
}
[data-theme="light"] .moyako-intro-title { color: #2D2D2D; }
[data-theme="light"] .moyako-intro-skill {
  color: #2D2D2D;
  background: rgba(255,255,255,0.6);
  border-color: rgba(0,0,0,0.1);
}

/* Legacy pre-grid children (icon/title/subtitle before a modal adopts
   .moyako-intro-section) still span both cols in row 1. Exclude
   .overlay-buttons / bare <button> so they don't steal row 1 when
   the modal has <3 pre-grid children. */
.moyako-difficulty-modal > :nth-child(1):not(.moyako-intro-section):not(.moyako-actions-section):not(.moyako-difficulty-grid):not(.overlay-buttons):not(button),
.moyako-difficulty-modal > :nth-child(2):not(.moyako-intro-section):not(.moyako-actions-section):not(.moyako-difficulty-grid):not(.overlay-buttons):not(button),
.moyako-difficulty-modal > :nth-child(3):not(.moyako-intro-section):not(.moyako-actions-section):not(.moyako-difficulty-grid):not(.overlay-buttons):not(button) {
  grid-column: 1 / -1;
  grid-row: 1;
  align-self: center;
  justify-self: center;
  text-align: center;
}
.moyako-difficulty-modal > .moyako-difficulty-grid {
  grid-column: 1;
  grid-row: 2;
  margin-bottom: 0;
  align-self: stretch;
}
.moyako-difficulty-modal > .moyako-difficulty-grid ~ button,
.moyako-difficulty-modal > .moyako-difficulty-grid ~ .overlay-buttons {
  grid-column: 2;
  grid-row: 2;
  align-self: stretch;
  margin-top: 0 !important;
  height: 100%;
  min-height: 0;
}
.moyako-difficulty-modal > .overlay-buttons {
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
}
/* Col-2 action buttons split the 5-pill column height evenly and wrap
   labels cleanly rather than breaking mid-word in a narrow column. */
.moyako-difficulty-modal > .moyako-difficulty-grid ~ button,
.moyako-difficulty-modal > .overlay-buttons > button {
  margin-top: 0 !important;
  width: 100%;
  flex: 1 1 0 !important;
  height: auto !important;
  min-height: 44px;
  font-size: 12px !important;
  line-height: 1.15 !important;
  padding: 8px 4px !important;
  white-space: normal;
  word-break: keep-all;
  overflow-wrap: break-word;
}
/* Very narrow screens — fall back to single-column stack so pills
   don't get squeezed below readable width. */
@media (max-width: 339px) {
  .moyako-difficulty-modal {
    grid-template-columns: 1fr;
  }
  .moyako-difficulty-modal > .moyako-difficulty-grid,
  .moyako-difficulty-modal > .moyako-difficulty-grid ~ button,
  .moyako-difficulty-modal > .moyako-difficulty-grid ~ .overlay-buttons {
    grid-column: 1;
  }
}

/* ============================================================
   Shared game-page mobile conventions (2026-04-23)
   Every body[data-no-bottom-nav][data-page-brand-label] except Sudoku
   (which runs its own bespoke mobile layout) inherits these:
     • no right-edge swipe drawer chevron — stats panel flows inline
     • stats panel static under the board
     • ad banner pinned to the bottom of the viewport
   Sudoku is explicitly excluded via :not([data-page-brand-label="Sudoku"]).
   ============================================================ */
@media (max-width: 1024px) {
  body[data-no-bottom-nav][data-page-brand-label]:not([data-page-brand-label="Sudoku"]) #moyako-drawer-toggle,
  body[data-no-bottom-nav][data-page-brand-label]:not([data-page-brand-label="Sudoku"]) #moyako-drawer-backdrop {
    display: none !important;
  }
  body[data-no-bottom-nav][data-page-brand-label]:not([data-page-brand-label="Sudoku"]) .moyako-stats-panel {
    position: static !important;
    transform: none !important;
    width: 100% !important;
    max-width: 100% !important;
    height: auto !important;
    max-height: none !important;
    box-shadow: none !important;
    border-left: 0 !important;
    padding: 8px !important;
    margin: 0 auto !important;
  }
  body[data-no-bottom-nav][data-page-brand-label]:not([data-page-brand-label="Sudoku"]) .moyako-game-shell {
    grid-template-columns: 1fr !important;
    grid-template-rows: auto auto !important;
  }
  body[data-no-bottom-nav][data-page-brand-label]:not([data-page-brand-label="Sudoku"]) #moyako-ad-bottom {
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    height: clamp(50px, 10dvh, 81px) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 0 8px !important;
    background: var(--moyako-bg, #1A1E2A) !important;
    z-index: 90 !important;
    box-sizing: border-box !important;
  }
  body[data-no-bottom-nav][data-page-brand-label]:not([data-page-brand-label="Sudoku"]) #moyako-ad-bottom > * {
    max-width: 100%;
    max-height: 100%;
  }
}

/* ============================================================
   Shared "landing overlay" template (2026-04-23)
   Any game's start overlay can opt in by adding .moyako-landing-screen
   to the outer overlay element (alongside .overlay / .moyako-overlay /
   whatever the game already uses for backdrop toggling).

   Effect: the overlay stops being a centred-modal-on-a-dim-backdrop
   and becomes a full-band landing screen between the brand bar (top
   50 px) and the ad banner (bottom ~10dvh). The .moyako-difficulty-
   modal inside it is forced to fill the band at 100 % height so the
   intro + actions sections split 50/50 based on the viewport.
   ============================================================ */
.moyako-landing-screen,
.overlay.moyako-landing-screen,
.moyako-overlay.moyako-landing-screen {
  position: fixed !important;
  top: 50px !important;
  left: 0 !important;
  right: 0 !important;
  bottom: 56px !important;                /* reserve the ad banner height */
  background: var(--moyako-bg, #1A1E2A) !important;
  z-index: 500 !important;
  padding: 12px !important;
  align-items: stretch !important;
  overflow: hidden !important;
}
/* ============================================================
   Clean landing template — one set of rules, no conflicts.
   Mobile portrait : intro stacked above actions (2 rows).
   Desktop/landscape: intro | actions side-by-side (2 cols).
   Modal sizes to its content, centred inside the landing band.
   ============================================================ */
.moyako-landing-screen {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  padding: 16px !important;
}
/* Sprint 5c — respect the [hidden] attribute so state-machine toggles
   (e.g. chess hidePicker() sets pickerState.hidden = true) can actually
   hide the overlay despite the display:flex !important above. */
.moyako-landing-screen[hidden] {
  display: none !important;
}
.moyako-landing-screen .overlay-content,
.moyako-landing-screen .moyako-overlay-content {
  max-width: none !important;
  width: 100% !important;
  max-width: 500px !important;
  height: auto !important;
  max-height: calc(100% - 16px) !important;
  margin: 0 !important;
  box-shadow: none !important;
  background: transparent !important;
  padding: 0 !important;
}
.moyako-landing-screen .moyako-difficulty-modal {
  display: grid !important;
  grid-template-columns: 1fr !important;
  grid-template-rows: auto auto !important;
  width: 100% !important;
  max-width: 100% !important;
  height: auto !important;
  max-height: 100% !important;
  gap: 12px !important;
  overflow: hidden !important;
}
/* Mobile portrait: intro row 1, actions row 2. */
.moyako-landing-screen .moyako-difficulty-modal > .moyako-intro-section {
  grid-column: 1 !important;
  grid-row: 1 !important;
}
.moyako-landing-screen .moyako-difficulty-modal > .moyako-actions-section {
  grid-column: 1 !important;
  grid-row: 2 !important;
}

@media (min-width: 769px), (orientation: landscape) and (min-width: 600px) {
  .moyako-landing-screen .overlay-content,
  .moyako-landing-screen .moyako-overlay-content {
    max-width: min(760px, 80vw) !important;
  }
  .moyako-landing-screen .moyako-difficulty-modal {
    grid-template-columns: 1fr 1fr !important;
    grid-template-rows: 1fr !important;
    gap: 14px !important;
  }
  .moyako-landing-screen .moyako-difficulty-modal > .moyako-intro-section {
    grid-column: 1 !important;
    grid-row: 1 !important;
  }
  .moyako-landing-screen .moyako-difficulty-modal > .moyako-actions-section {
    grid-column: 2 !important;
    grid-row: 1 !important;
  }
}

/* Desktop polish (≥1024) — modal grows to 1100px so the 2-col landing
   actually fills the viewport instead of sitting as a 760px island at
   1440+. Intro typography upsized so the intro column reads as a hero
   card, not a phone card centred in empty space. PR-6b.7 polish. */
@media (min-width: 1024px) {
  .moyako-landing-screen .overlay-content,
  .moyako-landing-screen .moyako-overlay-content {
    max-width: min(1100px, 90vw) !important;
  }
  .moyako-landing-screen .moyako-difficulty-modal > .moyako-intro-section {
    padding: 36px 28px !important;
    gap: 18px !important;
  }
  .moyako-landing-screen .moyako-intro-icon {
    font-size: 72px !important;
  }
  .moyako-landing-screen .moyako-intro-title {
    font-size: 36px !important;
    letter-spacing: 2px !important;
  }
  .moyako-landing-screen .moyako-intro-skill {
    font-size: 13px !important;
    padding: 6px 14px !important;
  }
  .moyako-landing-screen .moyako-intro-tier {
    font-size: 16px !important;
    padding: 8px 22px !important;
  }
  .moyako-landing-screen .moyako-difficulty-modal > .moyako-actions-section {
    padding: 20px 22px !important;
    gap: 14px 18px !important;
  }
  .moyako-landing-screen .moyako-actions-section .moyako-difficulty-btn {
    padding: 10px 16px !important;
    font-size: 15px !important;
  }
}

/* Hide the game shell when a landing overlay is visible. Each game's
   JS toggles the overlay differently; using per-game narrow selectors
   avoids false matches when an overlay is present but closed. */
body[data-page-brand-label="Chess"]:has(#startOverlay.active) .moyako-game-shell,
body[data-page-brand-label="Memory Game"]:has(#startOverlay.active) .moyako-game-shell,
body[data-page-brand-label="Maze"]:has(#startOverlay.active) .moyako-game-shell,
body[data-page-brand-label="Word Puzzle"]:has(#startOverlay:not(.hidden)) .moyako-game-shell,
body[data-page-brand-label="Backgammon"]:has(#bg-difficulty-overlay:not(.hidden)) .moyako-game-shell,
body[data-page-brand-label="Block Puzzle"]:has(#blockPuzzleStartOverlay:not(.hidden)) .moyako-game-shell {
  visibility: hidden !important;
}

/* Single-line tile at 44 px — Apple HIG tap-target minimum. */
.moyako-difficulty-btn {
  min-height: 44px;
}

.moyako-difficulty-name {
  font-weight: 700;
  font-size: var(--font-size-body);
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
  line-height: 1.2;
}

@media (max-width: 480px) {
  .moyako-difficulty-grid { gap: 6px; }
  .moyako-difficulty-btn { padding: 8px 10px; font-size: 13px; }
}

/* ============================================================
   Moyako Shared Game Shell (TASK-010)
   Canonical 3-panel layout used by every game page:
     Header (brand bar + back row) — from shared/components.js
     [ left-panel ] [ board-center ] [ right-panel ]
     Footer (bottom nav) — from shared/components.js

   Left panel: 🐼 panda coach reserved top 70% (future video/story),
               skills training compact 2-col grid bottom 30%.
   Right panel: game stats grid, difficulty row, controls, history,
                captured/end-state preview.

   Mobile ≤1024px collapses to single column with priority order:
   coach → board → stats → controls → history.
   ============================================================ */

.moyako-game-shell {
  display: grid;
  /* `auto` columns hug their content, so the side panels sit flush
     next to the board instead of stretching to fill leftover space
     (which left empty gaps between panels and the centered board).
     `justify-content: center` centers the whole trio in the viewport.
     `align-items: stretch` makes side panels grow to match the tallest
     column (the board), so their bottom edges align with the board's
     bottom — previously panels were shorter and left an uneven gap. */
  grid-template-columns: 240px auto 240px;
  justify-content: center;
  gap: var(--space-5);
  max-width: 1600px;
  margin: 0 auto;
  padding: var(--space-4);
  box-sizing: border-box;
  align-items: stretch;
  /* Explicit min-height so the shell isn't squeezed to whichever
     panel / board is currently the shortest. Caps at 820 px on huge
     monitors; floor uses (100dvh - 120 px) reserving just the brand
     bar + ad banner (bottom nav is opt-out via data-no-bottom-nav). */
  min-height: min(820px, calc(100dvh - 120px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)));
}

/* Game title at the top of the coach panel — replaces the old
   standalone page-header bar. User feedback 2026-04-12:
   "game name could be a bit colorful or dominant with frame" —
   gave it a brand-green gradient tile so it reads as the prominent
   name-plate for the current game (parallel to the tier-gradient
   difficulty pill on the opposite panel). */
.moyako-game-title {
  display: block;
  font-family: var(--font-display);
  font-size: var(--font-size-h3);
  color: #fff;
  text-align: center;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  background: linear-gradient(135deg, var(--moyako-primary) 0%, var(--moyako-primary-dark) 100%);
  padding: 10px 16px;
  border-radius: var(--radius-md);
  box-shadow: 0 4px 12px rgba(0,0,0,0.25);
  text-shadow: 0 1px 2px rgba(0,0,0,0.35);
  margin: 0;
  line-height: 1.15;
}

/* Friendly greeting line below the game title. Rendered by
   MoyakoComponents.renderGreeting() — personalized when the user is
   logged in (reads moyako_user from localStorage) and time-of-day
   based otherwise. Visually lighter than the title so the hierarchy
   reads Title > Greeting > Coach message. */
.moyako-game-greeting {
  font-size: var(--font-size-label);
  color: var(--moyako-text-muted);
  text-align: center;
  margin: 0 0 var(--space-2) 0;
  line-height: 1.3;
}

.moyako-coach-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--surface-panel);
  border: 1px solid var(--moyako-border-light);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--moyako-shadow-sm);
  color: var(--moyako-text);
  /* No forced min-height — the panel stretches to match the tallest
     grid row (usually the board) via align-items: stretch. If it has
     more content than the board height, the panel drives the row
     height and the board is vertically centered in its column.
     No overflow-y: auto — an earlier version hid Skills / Move History
     under a scroll fold on shorter viewports. */
}
/* Panda slot: ~70 % of panel height, reserved for future video/story
   interactions (TASK-010 Phase 2). For v1 just shows the panda asset
   + coach message. `flex: 7 1 0` gives it the first 70% slice;
   `.moyako-coach-skills` takes the rest via `margin-top: auto` so the
   skills block sticks to the bottom edge of the panel — when the panel
   stretches to match a tall board, the extra space lands inside
   coach-top (making room for future video/story content) rather than
   leaving a dead gap between coach-top and skills. */
.moyako-coach-top {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 8px;
  background: rgba(76,175,80,0.05);
  border-radius: 10px;
  min-height: 220px;
}
.moyako-coach-top img,
.moyako-coach-top .panda-avatar {
  width: 120px;
  height: auto;
  max-width: 100%;
}
.moyako-coach-message {
  font-size: var(--font-size-body);
  line-height: var(--line-height-text);
  color: var(--moyako-text);
  padding: var(--space-2) var(--space-1) 0;
}
/* Skills training block — stuck to the bottom of the coach panel via
   `margin-top: auto` so the panel's bottom edge visually aligns with
   the board's bottom edge (user feedback 2026-04-12). */
.moyako-coach-skills {
  margin-top: auto;
  flex: 0 0 auto;
  border-top: 1px solid var(--moyako-border-light);
  padding-top: var(--space-3);
}
.moyako-coach-skills h4 {
  font-size: var(--font-size-label);
  font-weight: 700;
  letter-spacing: var(--letter-spacing-uppercase);
  text-transform: uppercase;
  color: var(--moyako-text-muted);
  margin: 0 0 var(--space-3) 0;
}
.moyako-coach-skills ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2) var(--space-3);
}
.moyako-coach-skills li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--font-size-label);
  line-height: var(--line-height-ui);
  color: var(--moyako-text);
}

.moyako-stats-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--surface-panel);
  border: 1px solid var(--moyako-border-light);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  box-shadow: var(--moyako-shadow-sm);
  color: var(--moyako-text);
  /* If the panel has more content than the board height, it drives
     the grid row height — board centers in its column. We deliberately
     DO NOT clip with overflow-y: auto, which was hiding Move History +
     Captured below a scroll fold on shorter viewports. */
}
.moyako-stats-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}
.moyako-stat-box {
  background: var(--surface-panel-alt);
  border: 1px solid var(--moyako-border-light);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-3);
  text-align: center;
  color: var(--moyako-text);
}
/* Secondary label — --moyako-text-muted hits AAA contrast on both themes
   (7.6:1 light, 8.5:1 dark), replacing the previous opacity-0.75 hack. */
.moyako-stat-box > div:first-child {
  font-size: var(--font-size-label);
  color: var(--moyako-text-muted);
  text-transform: uppercase;
  letter-spacing: var(--letter-spacing-uppercase);
  line-height: var(--line-height-ui);
}
.moyako-stat-box > div:last-child {
  font-size: var(--font-size-value);
  font-weight: 700;
  color: var(--moyako-text-strong);
  margin-top: var(--space-1);
  line-height: 1.2;
}

.moyako-board-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Center the board vertically inside its grid column. When the side
     panels are taller than the board (common when the stats panel is
     scrolled to its content height), the board was pinned to the top
     leaving a visible gap underneath; center keeps it optically
     balanced. */
  justify-content: center;
  gap: 10px;
}

/* Bounded-scroll region inside a stats/coach panel — use this to wrap
   secondary content (move history, captured pieces, log, etc.) so the
   panel's overall height stays equal to the board's height while the
   secondary content scrolls internally when there's more of it than
   fits. Relies on the panel being a flex column. */
.moyako-panel-scroll {
  flex: 1 1 auto;
  /* Guaranteed minimum visible area so users always see at least a
     row or two of move history / captured pieces even when the parent
     row is short. Without this, flex: 1 1 0 + short panel collapses
     the region to 0 height and the content becomes invisible. */
  min-height: 140px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  scrollbar-width: thin;
}

/* ===================================================================
   OVERLAYS — shared game overlay pattern (difficulty picker, game-over)
   Nearly-opaque dark backdrop so the game board doesn't distract.
   All games inherit these; game-specific overrides go in the game's
   own <style> block.
   =================================================================== */
.moyako-overlay {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(10, 12, 18, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 16px;
}
.moyako-overlay.hidden { display: none; }
.moyako-overlay-content {
  background: var(--card-bg, #232838);
  color: var(--moyako-text-strong, #ECEFF4);
  border-radius: 16px;
  padding: 24px 22px;
  text-align: center;
  max-width: 340px;
  width: calc(100% - 48px);
  box-shadow: 0 24px 60px rgba(0,0,0,0.5);
  animation: moyako-slideUp 0.3s ease-out;
  /* keep the modal clear of the notch + home-indicator on iOS; env()=0 on
     web/Android → unchanged. CAP-SHELL-LAYOUT §2.9 */
  max-height: calc(100dvh - 32px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.moyako-overlay-title {
  font-size: var(--font-size-h3, 20px);
  font-weight: 700;
  margin-bottom: 6px;
  color: var(--moyako-text-strong, #ECEFF4);
}
.moyako-overlay-subtitle {
  font-size: var(--font-size-label, 13px);
  color: var(--moyako-text-muted, #888);
  margin-bottom: 16px;
}
@keyframes moyako-slideUp {
  from { transform: translateY(20px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@media (max-width: 768px) {
  .moyako-overlay-content { padding: 20px 16px; max-width: 340px; width: calc(100% - 32px); }
}

/* ===================================================================
   PLAYER CARDS v2 — 3-section stats panel (wireframe v11 approved).
   Section 1: You (hero avatar + name + scores + captures/pip)
   Section 2: Opponent (same layout)
   Section 3: Game (turn banner + clock/dice + move history)
   Buttons pinned to bottom.
   =================================================================== */

/* Player section — dominant background for player cards */
.moyako-player-section {
  border-radius: var(--radius-md, 10px);
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
  padding: 10px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}
.moyako-player-section.active-turn {
  background: rgba(76,175,80,0.12);
  border-color: rgba(76,175,80,0.4);
  box-shadow: 0 0 12px rgba(76,175,80,0.08);
}

/* Hero row — avatar + name + subtitle */
.moyako-hero-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  margin: -4px -4px 4px -4px;
}
.moyako-hero-row.white-header { background: rgba(240,240,240,0.10); border-bottom: 2px solid rgba(240,240,240,0.25); }
.moyako-hero-row.black-header { background: rgba(80,80,100,0.12); border-bottom: 2px solid rgba(100,100,120,0.25); }

/* Hero avatar — black fill, game-color border */
.moyako-hero-avatar {
  width: 56px; height: 56px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 32px; flex-shrink: 0;
  background: #1a1a2e;
  box-shadow: 0 3px 12px rgba(0,0,0,0.4);
}
.moyako-hero-avatar.white-side { border: 4px solid #f0f0f0; }
.moyako-hero-avatar.black-side { border: 4px solid #555; }
.moyako-hero-avatar.light-side { border: 4px solid #f0f0f0; }
.moyako-hero-avatar.dark-side  { border: 4px solid #555; }

.moyako-hero-info { flex: 1; }
.moyako-hero-name { font-weight: 700; font-size: 15px; margin-bottom: 2px; }
.moyako-hero-sub { font-size: 11px; color: var(--moyako-text-muted, #888); }

/* Score row layout. Badge APPEARANCE is canonical + theme-aware in
   moyako-layout.css §pane-right — `.page .pane-right :is(.pane-right-player,
   .moyako-player-section) .moyako-score-badge` (metallic chip, WCAG-AA, both
   themes). The old flat generic `.moyako-score-badge` rule was removed (#77)
   once all 7 games used the canonical chip; every badge element lives inside
   a pane-right player card, so the generic rule was fully overridden / dead. */
.moyako-scores-row { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }

/* Captures — visible but secondary */
.moyako-captures-row { margin-top: 6px; font-size: 20px; letter-spacing: 3px; min-height: 26px; opacity: 0.75; }
.moyako-captures-adv { font-size: 13px; color: #81C784; font-weight: 700; vertical-align: middle; margin-left: 6px; letter-spacing: 0; opacity: 1; }

/* Pip + home progress (backgammon) */
.moyako-pip-row { display: flex; justify-content: space-between; align-items: center; margin-top: 6px; }
.moyako-pip-val { font-size: 13px; color: #ccc; }
.moyako-pip-val strong { color: #fff; font-size: 16px; }
.moyako-home-bar { height: 8px; border-radius: 4px; background: rgba(255,255,255,0.08); margin-top: 4px; overflow: hidden; }
.moyako-home-fill { height: 100%; border-radius: 4px; background: #4CAF50; transition: width 0.3s; }

/* Turn dot */
.moyako-turn-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #4CAF50;
  display: inline-block; vertical-align: middle; margin-right: 4px;
  animation: moyako-pulse 1.5s ease-in-out infinite;
}
@keyframes moyako-pulse { 0%,100%{opacity:1} 50%{opacity:0.3} }

/* Turn banner */
.moyako-turn-banner { text-align: center; padding: 6px; border-radius: 8px; font-weight: 700; font-size: 14px; margin-bottom: 6px; }
.moyako-turn-banner.yours { background: rgba(76,175,80,0.15); color: #81C784; }
.moyako-turn-banner.theirs { background: rgba(255,152,0,0.12); color: #FFB74D; }

/* Big clock */
.moyako-big-clock { text-align: center; font-size: 32px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--moyako-text-strong, #ECEFF4); letter-spacing: 2px; margin: 4px 0; }
.moyako-big-clock.low { color: #EF5350; animation: moyako-clockPulse 1s ease-in-out infinite; }
@keyframes moyako-clockPulse { 0%,100%{opacity:1} 50%{opacity:0.6} }

/* Big dice (backgammon) */
.moyako-dice-area { display: flex; align-items: center; justify-content: center; gap: 10px; margin: 6px 0; }
.moyako-big-dice {
  width: 56px; height: 56px;
  border-radius: 12px;
  background: linear-gradient(180deg, #f5f5f5, #ddd);
  color: #1a1a2e;
  display: flex; align-items: center; justify-content: center;
  font-size: 28px; font-weight: 800;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4), inset 0 2px 0 rgba(255,255,255,0.8);
}
.moyako-roll-btn {
  flex: 1; padding: 14px;
  border-radius: 12px; font-size: 16px; font-weight: 800; text-align: center;
  background: linear-gradient(180deg, #2A3040, #1A1E2A);
  color: #81C784; border: 1px solid rgba(76,175,80,0.3); cursor: pointer;
}

/* Move counter row below dice */
.moyako-move-row { text-align: center; font-size: 11px; color: #666; margin-top: 4px; letter-spacing: 0.5px; }
.moyako-move-row strong { color: #aaa; font-size: 14px; }

/* Challenge tile (replaces difficulty pill in MP) */
.moyako-challenge-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: 10px 14px; border-radius: 10px;
  background: linear-gradient(135deg, rgba(107,142,250,0.2), rgba(74,111,232,0.12));
  border: 1px solid rgba(107,142,250,0.35);
  color: #90AAFF; font-weight: 700; font-size: 13px;
  margin-bottom: 8px; flex-shrink: 0;
}
.moyako-challenge-vs { font-size: 18px; font-weight: 800; color: #FFB74D; }

/* Match tracker — series dots */
.moyako-match-tracker { display: flex; align-items: center; justify-content: center; gap: 6px; }
.moyako-match-label { font-size: 10px; color: #888; text-transform: uppercase; letter-spacing: 0.5px; }
.moyako-match-dots { display: flex; gap: 4px; }
.moyako-match-dot { width: 14px; height: 14px; border-radius: 50%; border: 2px solid rgba(255,255,255,0.15); background: transparent; }
.moyako-match-dot.won { background: #4CAF50; border-color: #4CAF50; }
.moyako-match-dot.lost { background: #EF5350; border-color: #EF5350; }
.moyako-match-dot.current { border-color: #FFB74D; animation: moyako-pulse 1.5s ease-in-out infinite; }
.moyako-match-score { font-size: 16px; font-weight: 800; }
.moyako-match-score.green { color: #81C784; }
.moyako-match-score.red { color: #EF5350; }

/* Challenge banner (inline within opponent card) */
.moyako-challenge-banner { margin-top: 6px; padding: 6px 10px; border-radius: 8px; background: linear-gradient(135deg, rgba(255,152,0,0.15), rgba(255,87,34,0.10)); border: 1px solid rgba(255,152,0,0.3); font-size: 12px; color: #FFB74D; display: flex; align-items: center; gap: 6px; }

/* Game section — less dominant than player sections */
.moyako-game-section {
  border-radius: var(--radius-md, 10px);
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.06);
  padding: 10px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

/* Move history */
.moyako-move-list { flex: 1; overflow-y: auto; font-size: 11px; min-height: 0; margin-top: 4px; }
/* Empty-state hint — shows when the move list has no children, auto-hides once
   moves are added (Owner: move-history empty state was missing). NB: English in
   CSS content; i18n key follow-up if move lists need full localisation. */
.moyako-move-list:empty::before {
  content: "No moves yet";
  display: block; text-align: center; padding: 16px 8px;
  font-size: 13px; font-style: italic; opacity: 0.8;
  color: var(--text-muted, #888);
}
[data-theme="wooden"] .moyako-move-list:empty::before { color: #7B6857; }
/* Wooden — mute the parchment texture in the move history (Owner: lighter
   texture for paid-theme polish). Higher wash (0.72) than the shared 0.52. */
[data-theme="wooden"] .moyako-move-list {
  background:
    linear-gradient(rgba(247,235,207,0.72), rgba(247,235,207,0.72)),
    url("assets/wooden/parchment.png") repeat !important;
  background-size: auto, 360px auto !important;
}
.moyako-move-entry { display: flex; gap: 8px; padding: 1px 0; color: #8890a0; }
.moyako-move-num { color: #555; width: 16px; }

/* Game stats row */
.moyako-game-stats {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px; border-radius: var(--radius-md, 10px);
  background: var(--surface-panel-alt, rgba(255,255,255,0.04));
  border: 1px solid var(--moyako-border-light, rgba(255,255,255,0.08));
  font-size: 13px;
}
.moyako-game-stats-item { text-align: center; }
.moyako-game-stats-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--moyako-text-muted, #888); margin-bottom: 2px; }
.moyako-game-stats-value {
  font-size: 15px;
  font-weight: 700;
  color: var(--moyako-text-strong, #ECEFF4);
}

/* ===================================================================
   SHARED BUTTONS — consistent across all games.
   =================================================================== */
.btn {
  padding: 10px 18px;
  min-height: var(--tap-target-min, 44px);
  border: none;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  cursor: pointer;
  transition: all 0.2s;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  touch-action: manipulation;
  width: 100%;
  box-sizing: border-box;
}
.btn-primary {
  background: linear-gradient(135deg, #4CAF50, #388E3C);
  color: #fff;
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(76,175,80,0.3); }
.btn-secondary {
  background: var(--surface-panel-alt, rgba(255,255,255,0.05));
  color: var(--moyako-text, #e0e0e0);
  border: 1px solid var(--moyako-border-light, rgba(255,255,255,0.1));
}
.btn-secondary:hover { background: rgba(76,175,80,0.12); }

/* Compact "current difficulty" bar — a full-width pill that sits at the
   top of a game's stats panel, showing the selected tier with its
   tier-colored gradient. Click to open the difficulty modal and change
   tier. Replaces the old in-panel difficulty picker (5 emoji buttons)
   with a single prominent bar — industry pattern used by most puzzle
   games ("Current: Medium · change"). */
.moyako-difficulty-pill {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: var(--tap-target-md);
  padding: 8px 14px;
  border: 0;
  border-radius: 12px;
  color: #fff;
  font-weight: 700;
  font-size: var(--font-size-body);
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0,0,0,0.25);
  transition: transform 0.15s ease, box-shadow 0.2s ease;
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(255,255,255,0.3);
  position: relative;
}
.moyako-difficulty-pill:hover  { box-shadow: 0 6px 18px rgba(0,0,0,0.35); }
.moyako-difficulty-pill:active { transform: scale(0.98); }

/* Tier gradients — match .moyako-difficulty-btn so the pill visually
   inherits the tile the user picked. */
.moyako-difficulty-pill[data-tier="beginner"] { background: linear-gradient(135deg, #4DD0E1 0%, #0097A7 100%); }
.moyako-difficulty-pill[data-tier="easy"]     { background: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%); }
.moyako-difficulty-pill[data-tier="medium"]   { background: linear-gradient(135deg, #FF9800 0%, #E65100 100%); }
.moyako-difficulty-pill[data-tier="hard"]     { background: linear-gradient(135deg, #E53935 0%, #B71C1C 100%); }
.moyako-difficulty-pill[data-tier="expert"]   { background: linear-gradient(135deg, #9C27B0 0%, #4A148C 100%); }

.moyako-difficulty-pill-emoji { font-size: 18px; line-height: 1; }
.moyako-difficulty-pill-edit  {
  margin-left: auto;
  opacity: 0.8;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.3px;
}

@media (max-width: 1024px) {
  .moyako-game-shell {
    grid-template-columns: 1fr;
    gap: 14px;
    padding: 10px;
    /* Stop forcing a tall shell on mobile — let content flow. */
    min-height: 0;
  }
  /* Tablet order (769–1024px): board first, then coach, then stats —
     all still in-flow (single column stack). Phones (≤768px) get the
     board-first drawer layout below. */
  .moyako-board-center { order: 1; }
  .moyako-coach-panel  { order: 2; min-height: 0; }
  .moyako-stats-panel  { order: 3; min-height: 0; }

  .moyako-coach-top { min-height: 0; flex: none; padding: 4px; }
  .moyako-coach-top img,
  .moyako-coach-top .panda-avatar { width: 64px; }
  .moyako-coach-skills { flex: none; }
  .moyako-coach-skills ul { grid-template-columns: repeat(4, 1fr); }

  /* The prominent game-title gradient plate looks chunky at full
     width on a phone. Trim a bit so it doesn't dominate. */
  .moyako-game-title {
    font-size: var(--font-size-body-lg);
    padding: 8px 12px;
    letter-spacing: 1px;
  }
}

/* ============================================================
   PHONE OPTIMIZATION (≤768px) — see KNOW-HOW A26, DESIGN-RULES §2b
   Board-first layout. Coach panel hidden (marketing, not gameplay).
   Stats panel becomes an off-canvas right drawer toggled by a
   floating edge button. Brand bar collapses to logo + streak + ☰
   burger; sound/back/settings fold into the settings popup.
   Applies only to game pages (body[data-no-bottom-nav]).
   ============================================================ */

/* Drawer toggle + backdrop default: hidden everywhere; shown only
   on phone game pages via the @media block below. */
#moyako-drawer-toggle,
#moyako-drawer-backdrop { display: none; }

/* Centred panda mascot — shared 3-zone brand bar shows the mascot
   on every viewport size. Absolute-centred between brand-left (logo
   + title) and brand-right (streak chip + menu). */
#moyako-brand-bar .moyako-brand-panda-center {
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255,255,255,0.08);
  padding: 2px;
  box-sizing: border-box;
  box-shadow: 0 2px 6px rgba(0,0,0,0.35);
  object-fit: contain;
  pointer-events: none;
  z-index: 1;
}
#moyako-brand-bar {
  position: relative;
  /* Push brand bar below the device status bar / camera cutout. iPhones
     and Android phones with punch-hole or notch overlap the page top by
     ~24-44px; without this padding the system clock/signal icons paint
     over the "Moyako Sudoku" title. Capacitor WebView reports the inset
     correctly when viewport-fit=cover is set (already in place). */
  padding-top: env(safe-area-inset-top, 0px);
}
[data-theme="light"] #moyako-brand-bar .moyako-brand-panda-center {
  background: rgba(0,0,0,0.06);
}

/* The two icon spans inside the settings button — desktop shows ⚙️,
   phone swaps to ☰. Span classes set in components.js injectBrandBar. */
.moyako-icon-mobile { display: none; }

/* Quick-actions section default: hidden on tablet+desktop (sound + back
   live in the brand bar). The @media ≤768px block below overrides this. */
.moyako-quick-actions { display: none; }

@media (max-width: 768px) {
  /* --- Shell: board takes the whole viewport --- */
  .moyako-game-shell {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 6px;
    min-height: 0;
  }
  .moyako-board-center { order: 1; width: 100%; }

  /* ============================================================
     OPT-IN: quadrant shell — body[data-shell^="quadrant"]
     4-band vertical stack on phones:
       Brand bar  : fixed-top, 48-81 px (≈10dvh cap)
       Board area : 1fr (≈40% of viewport)
       Controls   : 1fr (≈40% of viewport)
       Ad banner  : fixed-bottom, 50-81 px (≈10dvh cap)
     All 4 bands span full width with a consistent 8 px side padding.
     Board + controls split the remaining 80 % 50/50.
     Board is centered (aspect-ratio 1), never trimmed — shrinks to
     fit its band instead.
     Games opt in with <body data-shell="quadrant" ...>.
     ============================================================ */
  body[data-shell^="quadrant"] {
    height: 100dvh;
    overflow: hidden;
    padding-top: clamp(48px, 10dvh, 81px) !important;
    padding-bottom: clamp(50px, 10dvh, 81px) !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  body[data-shell^="quadrant"] .moyako-game-shell,
  body[data-shell="quadrant-board"] .moyako-game-shell {
    display: grid !important;
    grid-template-columns: 1fr !important;
    gap: 8px !important;
    padding: 8px 8px !important;
    height: calc(100dvh - clamp(48px, 10dvh, 81px) - clamp(50px, 10dvh, 81px)) !important;
    width: 100% !important;
    min-height: 0 !important;
    box-sizing: border-box !important;
    overflow: hidden !important;
  }
  /* "quadrant": 40/40 equal split (board + controls same height). */
  body[data-shell="quadrant"] .moyako-game-shell {
    grid-template-rows: 1fr 1fr !important;
  }
  /* "quadrant-board": 45/35 board-priority split — board gets 9/16 of
     the middle 80 %, controls get 7/16. Same 10/10 header/ad bands. */
  body[data-shell="quadrant-board"] .moyako-game-shell {
    grid-template-rows: 9fr 7fr !important;
  }
  /* Row 1: board area — full width, centered square board */
  body[data-shell^="quadrant"] .moyako-board-center {
    grid-row: 1 !important;
    order: unset !important;
    width: 100% !important;
    min-width: 0;
    min-height: 0;
    display: flex !important;
    justify-content: center !important;
    align-items: center !important;
    padding: 0 !important;
    box-sizing: border-box;
  }
  body[data-shell^="quadrant"] .moyako-board-center > *,
  body[data-shell^="quadrant"] .board-wrapper {
    width: auto;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    aspect-ratio: 1;
    margin: 0 auto;
  }
  /* Row 2: stats panel — full width, docked in row */
  body[data-shell^="quadrant"] .moyako-stats-panel {
    grid-row: 2 !important;
    position: static !important;
    transform: none !important;
    box-shadow: none !important;
    border-radius: 8px !important;
    width: 100% !important;
    max-width: 100% !important;
    max-height: 100% !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 6px !important;
    overflow-y: auto !important;
    background: var(--moyako-bg) !important;
    z-index: auto !important;
  }
  /* Ad banner: fixed at the very bottom, inside the 10dvh body
     padding-bottom reservation. */
  body[data-shell^="quadrant"] #moyako-ad-bottom {
    position: fixed !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    height: clamp(50px, 10dvh, 81px) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 0 8px !important;
    box-sizing: border-box !important;
    z-index: 90 !important;
    background: var(--moyako-bg) !important;
  }
  body[data-shell^="quadrant"] #moyako-ad-bottom > * {
    max-width: 100%;
    max-height: 100%;
  }
  /* Drawer toggle + coach panel are irrelevant for quadrant shells. */
  body[data-shell^="quadrant"] #moyako-drawer-toggle,
  body[data-shell^="quadrant"] #moyako-drawer-backdrop,
  body[data-shell^="quadrant"] .moyako-coach-panel {
    display: none !important;
  }
  /* End of quadrant shell — everything below stays as legacy drawer pattern. */

  /* --- Hide the coach panel entirely on phones.
         The skills-training copy is marketing context, not gameplay.
         It still appears on tablet (769–1024px) and desktop. --- */
  .moyako-coach-panel { display: none; }

  /* --- Hide the game-title plate on phones; the brand bar + context
         already identify the page. Saves a full row above the board. --- */
  .moyako-game-title,
  .moyako-game-greeting { display: none; }

  /* --- Stats panel → right-edge off-canvas drawer ---
     Opaque background via var(--moyako-bg) — the default
     --surface-panel is rgba(255,255,255,0.06) in dark theme, which
     works inside a page-bg card but lets the chess board bleed through
     when the panel is floating as a drawer. Theme-aware solid color
     matches the page body so nothing ghosts through. */
  .moyako-stats-panel {
    position: fixed;
    top: 56px;
    right: 0;
    bottom: calc(70px + env(safe-area-inset-bottom, 0px));
    width: min(360px, 88vw);
    max-height: none;
    margin: 0;
    border-radius: 0;
    box-shadow: -12px 0 24px rgba(0,0,0,0.4);
    transform: translateX(100%);
    transition: transform 0.25s ease-out;
    z-index: 1100;
    overflow-y: auto;
    background: var(--moyako-bg);
  }
  body.moyako-drawer-open .moyako-stats-panel {
    transform: translateX(0);
  }

  /* --- Brand bar: logo + name + streak + burger only ---
     Compact across ALL game pages (body[data-no-bottom-nav]) at mobile
     widths. Individual games can fine-tune via a page-scoped override
     (e.g. body[data-page-brand-label="Sudoku"]).
     !important because components.js injects a later <style> with the
     desktop default padding (0.75rem 1rem = 12px 16px) which would
     otherwise inflate the bar to 75px on phones. */
  #moyako-brand-bar {
    flex-direction: row;
    /* padding-top includes status-bar inset so the bar clears the system
       clock + cutout on phones (env() falls back to 2px when the inset
       is 0 — desktop browsers + landscape phones with no top inset). */
    padding: calc(2px + env(safe-area-inset-top, 0px)) 10px 2px 10px !important;
    gap: 8px;
    min-height: 48px !important;
    position: relative;
  }
  #moyako-brand-bar .moyako-brand-icon {
    width: 40px !important;
    height: 40px !important;
    border-radius: 50% !important;
    background: rgba(255,255,255,0.08);
    padding: 2px;
    box-sizing: border-box;
    box-shadow: 0 2px 6px rgba(0,0,0,0.35);
  }
  [data-theme="light"] #moyako-brand-bar .moyako-brand-icon {
    background: rgba(0,0,0,0.06);
  }
  /* Centred panda mascot — absolute-centred between brand-left and
     brand-right so every game page shows the shared mascot emblem. */
  #moyako-brand-bar .moyako-brand-panda-center {
    display: block;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(255,255,255,0.08);
    padding: 2px;
    box-sizing: border-box;
    box-shadow: 0 2px 6px rgba(0,0,0,0.35);
    object-fit: contain;
    pointer-events: none;
    z-index: 1;
  }
  [data-theme="light"] #moyako-brand-bar .moyako-brand-panda-center {
    background: rgba(0,0,0,0.06);
  }
  .moyako-brand-motto { display: none; }
  .moyako-brand-name { font-size: 0.95rem; }
  .moyako-brand-back,
  #moyako-sound-btn { display: none !important; }

  /* Swap ⚙️ gear → ☰ burger inside the settings button */
  .moyako-icon-desktop { display: none; }
  .moyako-icon-mobile  { display: inline; }

  /* Body padding-top matches the compact 48 px bar + a 2 px breathing
     gap. !important because components.js injects a later <style> with
     the desktop default; on phones we want the tighter value. */
  body { padding-top: 50px !important; }

  /* --- Floating drawer toggle (right edge, mid-viewport) --- */
  body[data-no-bottom-nav] #moyako-drawer-toggle {
    display: flex;
    position: fixed;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    width: 36px;
    height: 72px;
    border: 0;
    border-radius: 10px 0 0 10px;
    background: var(--moyako-primary, #4CAF50);
    color: #fff;
    font-size: 18px;
    font-weight: 700;
    align-items: center;
    justify-content: center;
    box-shadow: -6px 0 14px rgba(0,0,0,0.35);
    cursor: pointer;
    z-index: 1200;
    transition: right 0.25s ease-out;
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(255,255,255,0.2);
  }
  body[data-no-bottom-nav].moyako-drawer-open #moyako-drawer-toggle {
    right: min(360px, 88vw);
  }

  /* --- Backdrop behind the open drawer (tap to close) --- */
  body[data-no-bottom-nav].moyako-drawer-open #moyako-drawer-backdrop {
    display: block;
    position: fixed;
    top: 56px;
    left: 0;
    right: 0;
    bottom: calc(70px + env(safe-area-inset-bottom, 0px));
    background: rgba(0,0,0,0.5);
    z-index: 1080;
    animation: moyako-fade-in 0.2s ease-out;
  }
  @keyframes moyako-fade-in { from { opacity: 0; } to { opacity: 1; } }

  /* --- Quick-actions section in the settings popup (phone only).
         Desktop shows sound + back directly in the brand bar, so
         this section is hidden there via the default rule above. --- */
  .moyako-quick-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin-bottom: 10px;
  }
}

/* ==========================================================================
   SHARED GAME CARD — TASK-011 golden-base alignment
   --------------------------------------------------------------------------
   Single source of truth for the game-tile card used on games.html,
   index.html (Featured Games) and anywhere else we showcase a game.
   Previously the two pages drifted (games.html used `.game-card`,
   index.html used `.step`). Consolidating here keeps hover, radius,
   padding and the 4-colour cycling top-border identical everywhere.

   Tokens intentionally fall back to hardcoded brand values so this class
   works even on pages that don't define --primary-green / --shadow-soft.
   ========================================================================== */
.moyako-game-card {
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 12px;
  padding: 24px;
  position: relative;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-soft, 0 2px 12px rgba(0, 0, 0, 0.3));
  transition: all 0.3s ease;
}
/* v466: the `display:flex` above (author rule) outranks the UA
 * [hidden]{display:none}, so a `hidden` game card stayed VISIBLE — the
 * staging-only "Game Template" tile leaked onto prod. Force [hidden] to win
 * so hidden cards are truly hidden (the localhost-only reveal script removes
 * the attribute for authors). */
.moyako-game-card[hidden] { display: none !important; }

.moyako-game-card:hover {
  border-left-color: var(--primary-green, #4CAF50);
  border-right-color: var(--primary-green, #4CAF50);
  border-bottom-color: var(--primary-green, #4CAF50);
  background: rgba(255, 255, 255, 0.14);
  box-shadow: 0 8px 32px rgba(76, 175, 80, 0.20);
  transform: translateY(-4px);
}

/* Default child typography so bare h3/p on the card render consistently.
   Pages that wrap headings in more-specific classes (e.g. .game-title
   on games.html) still win via specificity. */
.moyako-game-card h3 {
  font-family: var(--font-display, 'Plus Jakarta Sans', system-ui, sans-serif);
  font-size: 1.15rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
  color: #F5F7FA;
}
.moyako-game-card p {
  /* v398 — was hard-coded #C5CAD5; tokenised to pivot per theme. */
  color: var(--text-secondary, #C5CAD5);
  line-height: 1.6;
  margin: 0 0 0.5rem;
}
/* v398 — h3 also tokenised so cream themes get navy headings. */
.moyako-game-card h3 { color: var(--text-primary, #F5F7FA); }
/* Legacy light-theme overrides — now reading the same tokens, kept
 * as specificity safety nets since the base rule already covers them. */
[data-theme="light"] .moyako-game-card h3 { color: var(--text-primary, #0F172A); }
[data-theme="light"] .moyako-game-card p  { color: var(--text-secondary, #475569); }

/* Cycling accent top-border — matches the brand tile pattern */
.moyako-game-card:nth-child(4n+1) { border-top: 3px solid #66BB6A; }  /* green */
.moyako-game-card:nth-child(4n+2) { border-top: 3px solid #4DD0E1; }  /* cyan  */
.moyako-game-card:nth-child(4n+3) { border-top: 3px solid #FFD54F; }  /* yellow*/
.moyako-game-card:nth-child(4n)   { border-top: 3px solid #FF6B9D; }  /* pink  */

/* Coming-soon state */
.moyako-game-card[data-status="coming-soon"] { opacity: 0.65; }
.moyako-game-card[data-status="coming-soon"] .game-button,
.moyako-game-card[data-status="coming-soon"] .btn {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Honour prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  .moyako-game-card { transition: none; }
  .moyako-game-card:hover { transform: none; }
}

/* Light-theme override — silver/gray metallic tile (per user "may be
   silver/gray metallic background at tiles at light mode") with the
   4-colour cycling top border restated so the colored line stays
   visible after the side/bottom border-color override. */
[data-theme="light"] .moyako-game-card {
  background: linear-gradient(180deg, #F2F5FB 0%, #D8DFEC 100%);
  border: 1px solid rgba(15, 23, 42, 0.10);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    inset 0 -1px 0 rgba(15, 23, 42, 0.04),
    0 2px 6px rgba(15, 23, 42, 0.08),
    0 8px 18px rgba(15, 23, 42, 0.06);
  color: #0F172A;
}
[data-theme="light"] .moyako-game-card:nth-child(4n+1) { border-top: 3px solid #66BB6A; }
[data-theme="light"] .moyako-game-card:nth-child(4n+2) { border-top: 3px solid #4DD0E1; }
[data-theme="light"] .moyako-game-card:nth-child(4n+3) { border-top: 3px solid #FFD54F; }
[data-theme="light"] .moyako-game-card:nth-child(4n)   { border-top: 3px solid #FF6B9D; }
[data-theme="light"] .moyako-game-card:hover {
  transform: translateY(-6px) scale(1.02);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 1),
    inset 0 -1px 0 rgba(15, 23, 42, 0.05),
    0 6px 14px rgba(15, 23, 42, 0.10),
    0 16px 36px rgba(15, 23, 42, 0.14);
}

/* ==========================================================================
   SCORE BREAKDOWN — TASK-008 P2
   --------------------------------------------------------------------------
   Shows "Base 82 × Hard 1.2× = 98" on the game-over overlay so the user
   understands how the tier multiplier shaped their final score. Games
   opt-in by adding <div id="scoreBreakdown" class="score-breakdown-row">
   inside their overlay. Empty until renderStats() populates it.
   ========================================================================== */
.score-breakdown-row {
  margin: 10px 0 0;
  padding: 8px 10px;
  border-radius: 6px;
  background: rgba(76, 175, 80, 0.10);
  border: 1px solid rgba(76, 175, 80, 0.22);
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  letter-spacing: 0.01em;
  color: inherit;
  font-variant-numeric: tabular-nums;
}
.score-breakdown-row:empty {
  display: none;
}
.score-breakdown-row .sb-base,
.score-breakdown-row .sb-mult,
.score-breakdown-row .sb-final {
  display: inline-block;
  padding: 0 4px;
}
.score-breakdown-row .sb-mult {
  color: #FF9800;
  font-weight: 700;
}
.score-breakdown-row .sb-final {
  color: #4CAF50;
  font-weight: 800;
  font-size: 15px;
}
.score-breakdown-row .sb-op {
  opacity: 0.55;
  margin: 0 2px;
  font-weight: 400;
}
[data-theme="light"] .score-breakdown-row {
  background: rgba(37, 99, 235, 0.08);
  border-color: rgba(37, 99, 235, 0.18);
}
[data-theme="light"] .score-breakdown-row .sb-mult { color: #EA580C; }
[data-theme="light"] .score-breakdown-row .sb-final { color: #2563EB; }

/* ============================================================
   Rotate-to-portrait nudge — phone landscape only.
   Shows on viewports < 600 px wide AND in landscape orientation.
   Tablets (≥ 600 px wide) skip the nudge entirely; their landscape
   layouts are designed to work. Only applies to game pages
   (data-no-bottom-nav) — main site + landing pages are free to
   render however the user prefers.
   ============================================================ */
@media (max-width: 599px) and (orientation: landscape) {
  body[data-no-bottom-nav]::before {
    content: "📱  Rotate to portrait\A for the best experience";
    white-space: pre;
    position: fixed;
    inset: 0;
    z-index: 99999;
    background: rgba(10, 12, 18, 0.96);
    color: #ECEFF4;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 24px;
    font-size: 18px;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.5px;
    pointer-events: auto;
  }
}
