/* ==========================================================================
   ★ THEME ★ ────────────────────────────────────────────────────────────────
     name        : Default
     description : Parchment + fantasy. Warm cream parchment in light mode,
                   royal-obsidian black + burnished gold in dark mode.
                   Cinzel for monumental headings, Lora for body, Inter
                   for UI.
     author      : GameBeyond
     version     : 1.0
     supports    : light, dark
   ─────────────────────────────────────────────────────────────────────────

   This is THE theme file the site loads from `themes/Default/theme.css`.
   To switch the whole site to a different theme:

     1. Drop a sibling folder into `themes/` (e.g. `themes/Minimalist/`)
        with its own `theme.css` containing the same design-token shape
        (`:root` for light defaults, `html.theme-dark` for dark overrides).
     2. Repoint every `<link rel="stylesheet">` in each HTML <head>:
          themes/Default/theme.css   →   themes/Minimalist/theme.css

   Future automation: a SiteConfig.theme key + a tiny FOUC inline script
   could swap the href at first paint. Today it's a manual repoint —
   single source of truth: this file.

   ─────────────────────────────────────────────────────────────────────────
   Coding structure
   ────────────────
     1. Reset                          — universal box-sizing, margins
     2. Design tokens                  — `:root` (light) + `html.theme-dark`
                                          (dark overrides) for every color,
                                          spacing, font, shadow, border
     3. Base typography & elements     — h1-h6, p, a, em, strong, etc.
     4. Layout primitives              — `.container`, `.site-layout`, ad
                                          rails, page-intro, sticky banner
     5. Header / nav / footer          — site chrome
     6. Buttons & form controls        — `.btn`, `.cn-generate-btn`,
                                          select chrome, theme toggle
     7. Generator panels & cards       — `.cn-generator`, `.cn-card`,
                                          `.cn-results-grid`, hover states
     8. Recent Creations panel         — `.recent-list`, `.recent-name-item`
     9. Toast + animations             — `.toast-notification`, keyframes
    10. Responsive breakpoints         — @media adjustments
    11. Dark-theme overrides           — `html.theme-dark *` rules that
                                          patch hardcoded light-mode whites
                                          (Royal Obsidian palette + gold-
                                          framed cards live here)
   ──────────────────────────────────────────────────────────────────────── */


/* ╔══════════════════════════════════════════════════════════════════════╗
   ║  📱  RESPONSIVE STANDARD  —  read before adding any new CSS         ║
   ╚══════════════════════════════════════════════════════════════════════╝

   GameBeyond uses a strict 2-breakpoint, mobile-first responsive system.
   Stick to it and mobile will stop breaking on every feature add.

   ── Breakpoints (the ONLY two values allowed) ──────────────────────────
       Mobile   :  0     – 640px      ← base styles, no @media query
       Tablet+  :  641   – 1023px     ← @media (min-width: 641px)
       Desktop+ :  1024px and up      ← @media (min-width: 1024px)

   These also live as design-token references (informational only — CSS
   doesn't allow `var()` inside @media conditions):
       --bp-tablet  : 641px
       --bp-desktop : 1024px

   ── Rules ──────────────────────────────────────────────────────────────
     1. Write the MOBILE version FIRST (base rule, no @media).
     2. Use @media (min-width: 641px) ONLY for tablet+ enhancements.
     3. Use @media (min-width: 1024px) ONLY for true desktop layouts
        (side ad rail, multi-column grids, etc.).
     4. NEVER add new @media (max-width: …) queries for new code.
        (A small number of legacy max-width overrides remain, clearly
        labeled — leave them or migrate, but don't add more.)
     5. Never invent a third breakpoint. If 640 or 1024 doesn't fit,
        rethink the design before adding 480 / 768 / 1280.

   ── Mobile QA checklist  (verify at 360px-wide viewport) ───────────────
     [ ] Header fits on one row (no wrap onto a second line)
     [ ] All buttons / links have a ~44 × 44px tap target
     [ ] Content has ≥16px horizontal gutter (doesn't touch screen edges)
     [ ] Sticky bottom ad does NOT cover the last visible content
     [ ] No horizontal page scroll on any of the 5 pages
     [ ] Tapping a generator card copies the name; toast visible above ad
     [ ] Generate button is comfortably thumb-reachable
     [ ] Nav anchor jump (e.g. "Tools" → #tools) lands below the header

   ── Key responsive rules (search by selector to find them) ─────────────
     html               — scroll-padding-top (anchor offset) per breakpoint
     .container         — horizontal gutter scales 16 → 32 → 40px
     .site-header /
       .nav-bar /
       .nav-list        — compact on mobile (≤640), expanded on tablet+
     .site-layout       — single-column mobile, 2-col grid (main + 240px
                           ad rail) at ≥1024 when html.layout-ads-right
     .site-layout__aside — DISPLAY:NONE on mobile by design.
                            Mobile ads go through .site-sticky-ad only.
     .site-sticky-ad    — always-visible bottom banner, compacts ≤640
     .tools-grid        — 1col / 2col / 3col across the breakpoints
     .cn-* generator    — card grid compacts ≤640 (auto-fill minmax(120px))
   ────────────────────────────────────────────────────────────────────── */


/* Font @import is a belt-and-braces fallback — each HTML page also links
   the same Google Fonts stylesheet directly for faster rendering. */
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=Inter:wght@400;500;600&display=swap');

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

html {
  font-size: 80%;            /* Scale the entire site ~20% smaller.
                                Browser default is 16px → effective
                                base becomes 12.8px. Every rem-based
                                token inherits the reduction. */
  scroll-behavior: smooth;
  /* Prevent horizontal overflow — lives on <html> (not body) so the
     viewport itself clips, without creating a new block formatting
     context on <body> that would break position: sticky on the
     .site-header in some mobile browsers. */
  overflow-x: hidden;
  /* Offset anchor jumps (e.g. nav "Tools" → #tools) so the target
     section lands BELOW the sticky .site-header instead of being
     hidden underneath it. Default = desktop header (~92px) + ~16px
     breathing room = 108px. A media-query override below the
     `@media (max-width: 640px)` mobile header rule tightens this
     to 66px for the smaller mobile header. */
  scroll-padding-top: 108px;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }

/* --------------------------------------------------------------------------
   2. Design Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Responsive breakpoints — REFERENCE ONLY (CSS @media queries cannot
     use var(), so these are documentation tokens. Match these exact
     values in @media rules below. See the "Responsive Standard" header
     comment at the top of this file. */
  --bp-tablet:  641px;
  --bp-desktop: 1024px;

  /* Backgrounds */
  --bg-primary: #f9f3e8;
  --bg-secondary: #f4e4c1;
  --bg-card: #ffffff;
  --bg-dark: #2d1b00;
  --bg-dark-soft: #3d2817;

  /* Accents */
  --accent-primary: #8b2635;
  --accent-secondary: #a52a2a;
  --accent-gold: #C5A059;
  --accent-gold-highlight: #E2C17D;
  --accent-gold-soft: #c9a961;
  --accent-bronze: #cd7f32;

  /* Component color tokens — let the SHAPE rules in the base stylesheet
     use these and let the dark-mode block swap them. The result is one
     selector per component, with theme differences expressed purely as
     token overrides.

     Royal-Obsidian button (.cn-generate-btn): same sharp-cornered, gold-
     framed shape in both modes; only the surface gradient and text
     color flip per theme. */
  --btn-generate-bg:        linear-gradient(135deg, rgba(197, 160, 89, 0.10) 0%, rgba(226, 193, 125, 0.04) 100%);
  --btn-generate-bg-hover:  linear-gradient(135deg, var(--accent-gold) 0%, var(--accent-gold-highlight) 100%);
  --btn-generate-color:       #5d1822;
  --btn-generate-color-hover: #2d1b00;
  --btn-generate-text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3);
  --btn-generate-glow:        rgba(197, 160, 89, 0.30);
  --btn-generate-glow-hover:  rgba(226, 193, 125, 0.55);

  /* Royal-Obsidian result card (.cn-results-grid--wide .cn-card):
     solid surface + 1px subtle border + L-shaped gold corner accents.
     Tokens for the fill/border so light mode reads white-and-gold
     (matching the Character generator's `.cn-card` surface) while
     dark reads obsidian-and-gold from the SAME structural rule. */
  --card-wide-bg:          #ffffff;
  --card-wide-border:      rgba(212, 175, 55, 0.4);
  --card-wide-shadow:      0 4px 16px rgba(58, 45, 36, 0.08);

  /* Title halo — text-shadow color used by the brand text and the
     page-intro H1. Subtle gold rim in light mode, stronger gold glow
     in dark mode. Both modes share the same shape rule; only this
     color token swaps. */
  --halo-brand: rgba(212, 175, 55, 0.18);
  --halo-h1:    rgba(139, 38, 53, 0.10);

  /* Epithet flavor line — burnished gold reads well on cream parchment
     in light mode. Dark mode swaps to the brighter highlight gold. */
  --epithet-color: var(--accent-gold);

  /* Unified PANEL tokens — every visible main panel on the site
     (`.cn-generator`, `.prose`) reads from these so all pages render
     the same panel: warm cream parchment in light, near-obsidian in
     dark. Edit a token here and every page updates. */
  --panel-bg:      #f9f3e8;
  --panel-text:    var(--text-primary);
  --panel-border:  rgba(212, 175, 55, 0.4);
  --panel-radius:  16px;
  --panel-padding: 26px 20px;

  /* ★ STANDARD card sizing for every generator's name-button card. ★
     This fixes a single height across all entries in a batch so a
     Chinese name (with pinyin), a Norse name (with pronunciation),
     and an Elvish name (no subtitle) all render at the same button
     height. The text-stack inside the card vertically centers when
     content is shorter than this minimum; cards with extra-long
     content (e.g. 2-line wrapped names) still grow naturally —
     respecting accessibility — but the FLOOR is uniform.

     Future generators (city, faction, item, etc.) that use the
     `.cn-card` class get this size for free. */
  --card-min-height-wide: 77px;
  --card-min-height-grid: 104px;     /* Character generator gacha cards */

  /* Text */
  --text-primary: #2d1b00;
  --text-secondary: #5d4e37;
  --text-light: #8b7355;
  --text-white: #ffffff;
  --text-cream: #f4e4c1;

  /* Borders */
  --border-primary: #d4af37;
  --border-secondary: #c9a961;
  --border-subtle: #e8d4a8;

  /* Typography
     Latin-first stacks with CJK fallbacks appended so generated names
     containing Hanzi (e.g. "焰霸 (Yan Ba)") pick up a proper CJK serif
     per-glyph (browser font matching is character-by-character). */
  --font-heading: 'Cinzel', 'Crimson Text', Georgia, 'Times New Roman',
                  "Noto Serif SC", "Songti SC", "STSong", "SimSun",
                  "Microsoft YaHei", serif;
  --font-subheading: 'Lora', 'Libre Baskerville', Georgia,
                     "Noto Serif SC", "Songti SC", "STSong", "SimSun", serif;
  --font-body: 'Inter', 'Open Sans', -apple-system, BlinkMacSystemFont,
               "Segoe UI", Roboto,
               "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
               "Noto Sans CJK SC", sans-serif;

  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;
  --text-4xl: 2.25rem;
  --text-5xl: 3rem;

  /* Layout / radii
     -----------------------------------------------------------------
     Width scale — pick the SMALLEST size that fits the content.
     Every inner `max-width` on the site should reference one of these
     so page-to-page sizing stays consistent. New pages can either
     read these tokens directly in CSS, or use the .container--*
     modifier classes in HTML (see section 5). */
  --w-aside:     370px;   /* Narrow callouts, donation prompts        */
  --w-blurb:     493px;   /* Short paragraphs, card bodies            */
  --w-read:      598px;   /* Default reading width: intros, subtitles */
  --w-feature:   634px;   /* Feature lists, medium panels             */
  --w-panel:     704px;   /* Generator frames, wide cards             */
  --w-article:   722px;   /* Long-form prose: policies, terms, docs   */
  --w-main:      740px;   /* Site-wide left-panel cap — all pages     */
                          /* render at one consistent reading width.  */
  --w-page:     1056px;   /* Page shell (outer .container)            */

  /* Back-compat alias — older rules still reference --container-max. */
  --container-max: var(--w-page);

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;

  /* Shadows — warm brown tones */
  --shadow-sm: 0 2px 6px rgba(45, 27, 0, 0.08);
  --shadow-md: 0 6px 18px rgba(45, 27, 0, 0.12);
  --shadow-lg: 0 14px 32px rgba(45, 27, 0, 0.16);
  --shadow-gold: 0 0 0 3px rgba(212, 175, 55, 0.25);

  /* Transitions */
  --t-fast: 0.18s ease;
  --t-base: 0.3s ease;
}

/* --------------------------------------------------------------------------
   2b. Dark theme — flips the design tokens above.

   Applied via `.theme-dark` on <html> (set by js/site-theme.js + an inline
   FOUC-prevention snippet in each page's <head>). Accent colors (burgundy,
   gold, bronze) stay the same because they read well on both palettes.

   A handful of rules elsewhere in this file hardcode their backgrounds
   (e.g. `background: white`, gradient lockups, rgba(255,255,255,x) overlays)
   for the parchment look. Those get targeted overrides under section 22b
   so the whole site flips cleanly.
   -------------------------------------------------------------------------- */
html.theme-dark {
  /* ---- ROYAL OBSIDIAN palette ----
     Background: pure obsidian black, slight warm undertone for atmosphere.
     Text: antique parchment off-white, high contrast against obsidian.
     Gold: burnished base with a brighter highlight stop — used together
            in linear-gradients on borders and button hover for the
            "real metal frame" look.
     Stone grey: muted neutral for inactive borders / inner card edges. */
  --bg-primary:   #0D0D0D;          /* obsidian / deep charcoal */
  --bg-secondary: #141414;
  --bg-card:      #1a1a1a;
  --bg-dark:      #050505;          /* footer */
  --bg-dark-soft: #0d0d0d;

  /* Text — antique parchment off-white */
  --text-primary:   #F4EBD0;
  --text-secondary: #c9b89a;
  --text-light:     #6a6a6a;
  --text-white:     #ffffff;
  --text-cream:     #F4EBD0;

  /* Burnished gold — base + highlight for metallic gradients */
  --accent-gold:           #C5A059;
  --accent-gold-highlight: #E2C17D;

  /* Rose stays as the interactive accent (buttons, copy-pill hover,
     toasts) so action surfaces stand out against the gold/cream
     static-text palette. */
  --accent-primary:   #e85866;
  --accent-secondary: #f57580;

  /* Component color overrides — only colors swap; the shape/typography
     rules in the base stylesheet stay identical across modes. */
  --btn-generate-bg:        linear-gradient(135deg, rgba(197, 160, 89, 0.18) 0%, rgba(226, 193, 125, 0.10) 100%);
  --btn-generate-bg-hover:  linear-gradient(135deg, var(--accent-gold) 0%, var(--accent-gold-highlight) 100%);
  --btn-generate-color:       var(--accent-gold-highlight);
  --btn-generate-color-hover: #0D0D0D;
  --btn-generate-text-shadow: 0 0 8px rgba(226, 193, 125, 0.5);
  --btn-generate-glow:        rgba(197, 160, 89, 0.40);
  --btn-generate-glow-hover:  rgba(226, 193, 125, 0.60);

  --card-wide-bg:          rgba(0, 0, 0, 0.6);
  --card-wide-border:      var(--border-subtle);   /* stone grey */
  --card-wide-shadow:      0 4px 20px rgba(0, 0, 0, 0.6),
                           inset 0 0 0 1px rgba(197, 160, 89, 0.05);

  --halo-brand: rgba(197, 160, 89, 0.35);
  --halo-h1:    rgba(244, 235, 208, 0.15);

  --epithet-color: var(--accent-gold-highlight);

  /* Panel tokens — near-obsidian fill with warm undertone, soft gold
     border stays consistent in dark mode for the parchment-on-obsidian
     read. */
  --panel-bg:      #0f0d0b;
  --panel-border:  rgba(212, 175, 55, 0.28);

  /* Borders — muted stone grey for inactive states; gold tokens above
     are used by the metallic-frame mixin where structure matters. */
  --border-primary:   #C5A059;
  --border-secondary: #4A4A4A;
  --border-subtle:    #4A4A4A;

  /* Shadows — deeper for the obsidian look */
  --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.6);
  --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.7);
  --shadow-lg: 0 14px 40px rgba(0, 0, 0, 0.8);
  --shadow-gold: 0 0 0 3px rgba(197, 160, 89, 0.28);
}

/* Vignette — radial gradient lifts the page center to charcoal and
   fades to pure black at the edges, giving the obsidian background
   subtle depth instead of looking flat. background-attachment: fixed
   keeps the vignette anchored to the viewport during scroll. */
html.theme-dark body {
  background-color: var(--bg-primary);
  background-image:
    radial-gradient(ellipse at 50% 35%,
      rgba(40, 32, 18, 0.55) 0%,
      rgba(20, 16, 10, 0.30) 38%,
      rgba(0, 0, 0, 0)        70%);
  background-attachment: fixed;
}
html.theme-dark body::before {
  opacity: 0.12;
}

/* The Royal Obsidian button shape (.cn-generate-btn), card frame
   (.cn-results-grid--wide .cn-card with L-shaped gold corner accents),
   and hero typography (Cinzel + 2.5rem) all live in the base
   stylesheet and apply to BOTH light and dark modes. The dark-mode
   block here only flips color tokens (--btn-generate-*, --card-wide-*,
   --halo-*, --accent-primary, etc.); everything structural is shared.
   Adding a new component override here should be the rare exception,
   not the rule.

   .page-intro h1 in dark mode reads in cream (--text-primary)
   automatically because the color rule on h1 is `color: var(--accent-primary)`
   and accent-primary is overridden to a brighter rose in dark mode.
   The hero h1 specifically wants cream-not-rose, so we override it
   here as a single-property tweak. */
html.theme-dark .page-intro h1 {
  color: var(--text-primary);
}

/* Sticky header uses a translucent white overlay in light mode; flip it
   to a translucent dark overlay so the blur still reads. */
html.theme-dark .site-header {
  background: rgba(20, 16, 12, 0.88);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
}
/* Mobile: fixed ☰ button + dropdown overlay in dark mode. */
html.theme-dark .nav-toggle {
  background: var(--bg-dark);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
html.theme-dark .nav-bar > nav {
  background: rgba(20, 16, 12, 0.96);
}

/* Ad-slot placeholder — the dashed parchment box reads as a paper cut-out
   in light mode; make it a dashed charcoal block in dark. */
html.theme-dark .ad-slot {
  background: rgba(255, 255, 255, 0.02);
  border-color: var(--border-secondary);
}

/* --------------------------------------------------------------------------
   2d. Sticky bottom ad banner (universal, session-dismissible)

   Locked to the bottom of the viewport via position: fixed. Spans 100%
   width, capped at ~90px height on desktop and ~60px on mobile so it
   never dominates the viewport. The body reserves equivalent
   padding-bottom so fixed-position content doesn't cover the footer
   when the user scrolls all the way down.

   When dismissed, JS adds `.is-dismissed` on the banner AND
   `.ad-dismissed` on <body>, which also removes the reserved padding.
   The dismissal persists via sessionStorage (current tab only — a new
   tab or fresh session shows it again).
   -------------------------------------------------------------------------- */
body {
  /* Reserve room at the bottom of every page for the sticky banner.
     Removed when the user dismisses it (body.ad-dismissed below). */
  padding-bottom: 98px;
}

.site-sticky-ad {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  max-height: 90px;
  min-height: 60px;
  /* Also hard-cap against viewport — prevents the banner from eating
     more than 15% of a short viewport on phones. */
  max-height: min(90px, 15vh);
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 12px;
  background: var(--bg-card);
  border-top: 2px solid var(--border-primary);
  box-shadow: 0 -4px 18px rgba(45, 27, 0, 0.14);
  /* Respect the device safe-area on iOS (iPhone X+ notch/home indicator) */
  padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px));
  transition: transform 0.3s ease, opacity 0.2s ease;
}


/* The slot itself — hosts the AdSense <ins> tag in production, or the
   placeholder text until one is pasted in. Capped at the standard
   728x90 leaderboard width so it stays centered on wide screens. */
.site-sticky-ad__slot {
  width: 100%;
  max-width: 728px;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.site-sticky-ad__placeholder {
  font-family: var(--font-body);
  font-size: 0.75rem;
  color: var(--text-light);
  letter-spacing: 2px;
  text-transform: uppercase;
}

/* Close button removed — sticky ad is permanent. */

/* Mobile: shrink the banner footprint and trim body padding. */
@media (max-width: 640px) {
  body { padding-bottom: 68px; }
  .site-sticky-ad {
    min-height: 50px;
    max-height: min(60px, 15vh);
    padding: 4px 8px;
    padding-bottom: calc(4px + env(safe-area-inset-bottom, 0px));
  }
}

/* Dark-theme treatment — darker surface, softer border. */
html.theme-dark .site-sticky-ad {
  background: #1a1411;
  border-top-color: var(--border-secondary);
  box-shadow: 0 -4px 22px rgba(0, 0, 0, 0.55);
}

/* Sticky-bottom ad toggle (ads.stickyBottom.enabled = false in site-config.js).
   When off, hide the banner AND drop the body padding-bottom reserve so the
   footer doesn't carry a ghost gutter. */
html.layout-no-sticky-ad .site-sticky-ad { display: none; }
html.layout-no-sticky-ad body            { padding-bottom: 0; }

/* --------------------------------------------------------------------------
   2d². Site layout — main + optional right ad rail
   Controls the site-wide page skeleton. Toggled via SiteConfig.ads.rightPanel
   in js/site-config.js (read at first paint by the inline FOUC script in
   each page's <head>, which adds `html.layout-ads-right` when enabled).

   Structure (every page):
     <main class="container site-layout">
       <div class="site-layout__main"> ...actual page content... </div>
       <aside class="site-layout__aside">
         <div class="site-ad-rail"> ...ad slot... </div>
       </aside>
     </main>

   Behavior:
     • Default (no class, or mobile/tablet <1024px):
         aside is display:none, main flows full-width. Nothing to
         work around on mobile — it just doesn't exist there.
     • With `html.layout-ads-right` + viewport ≥1024px:
         .site-layout becomes a 2-col grid (fluid main + 300px rail),
         aside is visible and scrolls NATURALLY alongside main content
         (not sticky) so additional ad units can be stacked vertically.
     • Flipping rightPanel.enabled off removes the class on <html>,
         which immediately un-grids .site-layout and un-hides the
         aside → main content auto-expands to fill.

   Stacking more ads: drop additional `.site-ad-rail` elements inside
   `.site-layout__aside`. The aside is a flex column with gap, so each
   new rail stacks below the previous one with consistent spacing.
   -------------------------------------------------------------------------- */
/* Site-wide left-panel bounds — every page's main column caps at the
   same `--w-main` so panels (.cn-generator, .prose, .about-intro,
   .support-card) all render at one consistent width regardless of
   what wraps them. Centered via auto margins for pages that don't
   have a right ad rail; in grid mode the cap still applies but the
   grid cell governs final placement. */
.site-layout__main {
  width: 100%;
  max-width: var(--w-main);
  margin-left: auto;
  margin-right: auto;
}

.site-layout__aside { display: none; }

@media (min-width: 1024px) {
  html.layout-ads-right .site-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 240px;
    gap: 24px;
    align-items: start;
  }
  html.layout-ads-right .site-layout__aside {
    display: flex;
    flex-direction: column;
    gap: 24px;
    /* Scrolls with the main content — no `position: sticky`. This lets
       us stack multiple ad units in the rail without the viewport
       clipping anything past the first screen. */
  }
}

/* The actual ad unit container. Styled as a subtle parchment card so
   the empty state (before AdSense fills) doesn't look broken.
   Default is 300×250 (IAB Medium Rectangle). Use `.site-ad-rail--tall`
   for 300×600 (IAB Half-Page). Stack as many rails as you like inside
   `.site-layout__aside` — they scroll with the page. */
.site-ad-rail {
  min-height: 200px;
  padding: 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  font-family: var(--font-subheading);
  font-size: 0.8rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  flex: 0 0 auto;       /* don't let flex-col parent stretch/shrink us */
}

/* Half-page (300×600) — taller rail for higher-value placements. */
.site-ad-rail--tall { min-height: 480px; }

html.theme-dark .site-ad-rail {
  background: #1a1411;
  border-color: var(--border-secondary);
}

/* --------------------------------------------------------------------------
   2c. Theme-toggle button (universal, lives in the nav right of Privacy)
   -------------------------------------------------------------------------- */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  font-size: 16px;
  line-height: 1;
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color var(--t-fast),
              color var(--t-fast),
              background var(--t-fast),
              transform var(--t-fast);
}

.theme-toggle:hover,
.theme-toggle:focus-visible {
  border-color: var(--accent-gold);
  color: var(--accent-gold);
  transform: rotate(-12deg);
  outline: none;
}

/* --------------------------------------------------------------------------
   3. Base / body
   -------------------------------------------------------------------------- */
body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.65;
  color: var(--text-primary);
  background-color: var(--bg-primary);
  background-image:
    radial-gradient(circle at 18% 8%, rgba(212, 175, 55, 0.10), transparent 45%),
    radial-gradient(circle at 82% 92%, rgba(139, 38, 53, 0.06), transparent 45%);
  min-height: 100vh;
  /* overflow-x: hidden — moved to <html> to avoid breaking
     position: sticky on .site-header in mobile browsers. */
  position: relative;
  animation: fadeIn 0.5s ease-out;
}

/* Subtle paper grain overlay — inline SVG, zero extra requests */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220' viewBox='0 0 220 220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.18  0 0 0 0 0.11  0 0 0 0 0  0 0 0 0.06 0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.5;
}

body > * { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   4. Typography
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-heading);
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.22;
  letter-spacing: 0.5px;
}

h1 {
  font-size: clamp(2rem, 5.5vw, var(--text-5xl));
  color: var(--accent-primary);
  text-shadow: 0 0 16px var(--halo-h1);
}

h2 {
  font-size: clamp(1.5rem, 3.5vw, var(--text-4xl));
  color: var(--accent-primary);
  margin-bottom: 1rem;
}

h3 {
  font-family: var(--font-subheading);
  font-size: var(--text-xl);
  margin-bottom: 0.5rem;
  color: var(--text-primary);
}

p { color: var(--text-secondary); margin-bottom: 1rem; }
strong { color: var(--text-primary); }
em { color: var(--accent-primary); font-style: italic; }

a { color: var(--accent-primary); transition: color var(--t-fast); }
a:hover, a:focus-visible { color: var(--accent-secondary); text-decoration: underline; }

:focus-visible {
  outline: 3px solid var(--accent-gold);
  outline-offset: 3px;
  border-radius: 3px;
}

/* --------------------------------------------------------------------------
   5. Layout

   Every page's outermost content wrapper is `.container`. It caps at
   --w-page (1200px) and has responsive side padding that grows with
   the viewport:
     mobile  (<768px): 20px
     tablet  (≥768px): 32px
     desktop (≥1024px): 40px

   For pages whose content wants a NARROWER inner cap (reading-heavy
   pages, policy pages, intro panels), chain a modifier class:

     <main class="container container--article">   (820px — prose pages)
     <main class="container container--panel">     (800px — generator pages)
     <section class="container container--reading">(680px — marketing intros)

   This replaces ad-hoc per-component `max-width: Npx` and keeps every
   page on the same width scale. New components should read the width
   tokens (var(--w-aside) … var(--w-page)) rather than raw pixels.
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--w-page);
  margin: 0 auto;
  /* Mobile-first gutter — scales up at tablet (641px) and desktop
     (1024px) breakpoints below. NEVER set this to 0 — content
     touching screen edges is the #1 mobile complaint. */
  padding: 0 16px;
}
/* Inner-cap modifiers — stack on .container to narrow the content column. */
.container--article { max-width: var(--w-article); }   /* 820px — prose */
.container--panel   { max-width: var(--w-panel);   }   /* 800px — frames */
.container--feature { max-width: var(--w-feature); }   /* 720px — lists */
.container--reading { max-width: var(--w-read);    }   /* 680px — intros */
.container--blurb   { max-width: var(--w-blurb);   }   /* 560px — callouts */

main { padding: 2rem 0 4rem; }
section { margin-bottom: 3rem; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent-primary);
  color: var(--text-white);
  padding: 8px 14px;
  font-weight: 700;
  z-index: 1000;
  border-radius: var(--radius-sm);
}
.skip-link:focus { left: 12px; top: 12px; }

/* --------------------------------------------------------------------------
   6. Header / Navigation
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(249, 243, 232, 0.94);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 2px solid var(--border-primary);
  box-shadow: 0 2px 8px rgba(45, 27, 0, 0.05);
}

.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  padding: 27px 0;          /* ~92px total header height (10% taller
                                than the previous ~84px size). bump
                                scroll-padding in `html` rule if this
                                changes again. */
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.brand-name {
  font-family: var(--font-heading);
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--accent-primary);
  letter-spacing: 2px;
  text-transform: uppercase;
  text-shadow: 0 0 12px var(--halo-brand);
  transition: color var(--t-fast), text-shadow var(--t-fast);
}
.brand:hover .brand-name,
.brand:focus-visible .brand-name {
  color: var(--accent-gold);
  text-shadow: 0 0 18px var(--halo-brand), 0 0 6px rgba(197, 160, 89, 0.25);
  text-decoration: none;
}

.brand-tagline {
  font-family: var(--font-subheading);
  font-size: 0.85rem;
  color: var(--text-light);
  font-style: italic;
}

.nav-list {
  display: flex;
  gap: 18px;
  align-items: center;
}

/* Hamburger toggle — hidden by default (desktop+); shown only on mobile.
   Sits beside the brand on the right; clicking it expands the .nav-list
   into a vertical dropdown below the header. JS wiring lives in
   js/site-nav.js (sets data-nav-open on .nav-bar + aria-expanded here). */
.nav-toggle {
  display: none;             /* hidden on tablet+ — see mobile @media */
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: transparent;
  border: 1px solid var(--border-primary);
  border-radius: 8px;
  color: var(--text-primary);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.nav-toggle:hover,
.nav-toggle:focus-visible {
  background: var(--bg-secondary);
  border-color: var(--accent-primary);
  outline: none;
}

.nav-list a {
  color: var(--text-primary);
  font-size: 1.05rem;
  font-weight: 500;
  padding: 6px 4px;
  position: relative;
  transition: color var(--t-fast);
}

.nav-list a:hover,
.nav-list a:focus-visible {
  color: var(--accent-primary);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent-primary);
}

/* Active page — highlighted gold text, no underline.
   Standard for all current and future page links across the site.
   `main.js → highlightActiveNav()` adds `.is-active` + `aria-current`
   to the matching <a data-nav> on each page load. */
.nav-list a.is-active {
  color: var(--accent-gold);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   7. Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 12px 28px;
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: 0.3px;
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: center;
  transition:
    transform var(--t-base),
    background var(--t-base),
    color var(--t-base),
    box-shadow var(--t-base),
    border-color var(--t-base);
  user-select: none;
}

.btn-primary {
  background: var(--accent-primary);
  color: var(--text-white);
  border-color: var(--accent-primary);
  box-shadow: var(--shadow-sm);
}
.btn-primary:hover,
.btn-primary:focus-visible {
  background: var(--accent-secondary);
  border-color: var(--accent-gold);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md), var(--shadow-gold);
  text-decoration: none;
}

.btn-secondary {
  background: var(--bg-card);
  color: var(--accent-primary);
  border-color: var(--accent-primary);
}
.btn-secondary:hover,
.btn-secondary:focus-visible {
  background: var(--accent-primary);
  color: var(--text-white);
  border-color: var(--accent-gold);
  text-decoration: none;
}

.btn-disabled,
.btn[disabled] {
  background: var(--border-subtle);
  color: var(--text-light);
  border-color: transparent;
  cursor: not-allowed;
  box-shadow: none;
  pointer-events: none;
}

.btn-lg { padding: 16px 36px; font-size: var(--text-lg); }
.btn-sm { padding: 8px 14px; min-height: 36px; font-size: var(--text-sm); }

/* --------------------------------------------------------------------------
   8. Ornamental flourishes (disabled — kept as placeholder for future use)
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   9. Hero
   -------------------------------------------------------------------------- */
.hero {
  text-align: center;
  padding: 3rem 0 2rem;
}

.hero h1 { margin-bottom: 1rem; }

.hero .subtitle {
  font-family: var(--font-subheading);
  font-size: clamp(1.05rem, 2.2vw, var(--text-xl));
  color: var(--text-secondary);
  max-width: var(--w-read);
  margin: 0 auto 2rem;
  font-style: italic;
}

/* --------------------------------------------------------------------------
   10. Tool / Persona Cards (shared)
   -------------------------------------------------------------------------- */
.tools-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: 1.5rem;
}

.tool-card {
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-top: 4px solid var(--accent-gold);
  border-radius: var(--radius-md);
  padding: 28px 22px;
  text-align: center;
  box-shadow: var(--shadow-sm);
  transition:
    transform var(--t-base),
    box-shadow var(--t-base),
    border-color var(--t-base);
  position: relative;
  overflow: hidden;
}

.tool-card:hover,
.tool-card:focus-within {
  transform: translateY(-4px);
  border-top-color: var(--accent-primary);
  box-shadow: var(--shadow-lg);
}

.tool-card.is-disabled { opacity: 0.6; }
.tool-card.is-disabled:hover {
  transform: none;
  box-shadow: var(--shadow-sm);
  border-top-color: var(--border-secondary);
}

.tool-icon {
  font-size: 3rem;
  margin-bottom: 0.75rem;
  line-height: 1;
  filter: drop-shadow(0 2px 4px rgba(45, 27, 0, 0.15));
}

.tool-card h3 {
  font-family: var(--font-heading);
  color: var(--accent-primary);
  margin-bottom: 0.5rem;
  font-size: var(--text-xl);
  letter-spacing: 1px;
  text-transform: uppercase;
}

.tool-card p {
  flex-grow: 1;
  margin-bottom: 1.25rem;
  font-size: 0.95rem;
  color: var(--text-secondary);
}

.tool-card.is-plain p { margin-bottom: 0; }

.tool-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  padding: 4px 12px;
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 0.75rem;
  font-family: var(--font-body);
}
.tool-badge.live {
  background: #f0e4c2;
  color: #6b4f0f;
  border: 1px solid var(--accent-gold);
}
.tool-badge.soon {
  background: rgba(45, 27, 0, 0.04);
  color: var(--text-light);
  border: 1px solid var(--border-subtle);
}

/* --------------------------------------------------------------------------
   11. Homepage "About preview"
   -------------------------------------------------------------------------- */
.about-preview {
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 2.25rem 1.75rem;
  margin-top: 2rem;
  box-shadow: var(--shadow-sm);
  text-align: center;
}

.about-preview h2 { margin-bottom: 0.6rem; }
.about-preview h2::after {
  content: "❦";
  display: block;
  text-align: center;
  color: var(--accent-gold);
  font-size: 1.2rem;
  margin-top: 0.3rem;
  margin-bottom: 0.4rem;
}
.about-preview p {
  max-width: var(--w-read);
  margin: 0 auto 1.2rem;
}
.learn-more {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-subheading);
  font-weight: 600;
  color: var(--accent-primary);
  border-bottom: 2px solid transparent;
  padding-bottom: 2px;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.learn-more:hover,
.learn-more:focus-visible {
  text-decoration: none;
  border-bottom-color: var(--accent-gold);
  color: var(--accent-secondary);
}

/* --------------------------------------------------------------------------
   12. About page — "Who We're For" intro + "Why Us" + Support
   -------------------------------------------------------------------------- */
.about-intro {
  max-width: var(--w-main);   /* match Dragon panel width site-wide */
  margin: 0 auto 2.5rem;
  text-align: center;
  padding: 0 0.5rem;
}
.about-intro p {
  font-size: var(--text-lg);
  font-family: var(--font-subheading);
  color: var(--text-secondary);
}

/* Justified variant — used where the prose carries narrative weight
   (the About page's personal story sections) so paragraph edges align
   on both sides for a more booklike read. Adds a touch of inter-word
   space to keep stretched lines from looking thin. */
.about-intro--justified {
  text-align: justify;
}
.about-intro--justified p {
  hyphens: auto;
  -webkit-hyphens: auto;
}

.section-heading {
  text-align: center;
  margin-bottom: 1.5rem;
}
.section-heading h2 {
  display: inline-block;
  padding-bottom: 0.5rem;
  border-bottom: 2px solid var(--accent-gold);
}

/* (.why-us removed — the "What Makes Us Different" About section
   was deleted in the personal-narrative About rewrite.) */

.support-card {
  max-width: var(--w-main);   /* match Dragon panel width site-wide */
  margin: 3rem auto 0;
  background: var(--bg-card);
  border: 1px solid var(--border-subtle);
  border-top: 4px solid var(--accent-gold);
  border-radius: var(--radius-md);
  padding: 2rem 1.5rem;
  text-align: center;
  box-shadow: var(--shadow-sm);
}
.support-card h2 { margin-bottom: 0.75rem; }
.support-card p { max-width: var(--w-blurb); margin: 0 auto 1.5rem; }

.about-cta {
  text-align: center;
  margin-top: 2.5rem;
}

/* --------------------------------------------------------------------------
   13. Donation prompt (Dragon Name Generator page)
   -------------------------------------------------------------------------- */
.donation-prompt {
  max-width: var(--w-aside);
  margin: 1.5rem auto;
  padding: 14px 18px;
  background: var(--bg-secondary);
  border: 1px solid var(--accent-gold);
  border-radius: var(--radius-sm);
  text-align: center;
  font-size: 0.95rem;
  color: var(--text-secondary);
  box-shadow: var(--shadow-sm);
}
.donation-prompt p { margin: 0; color: var(--text-secondary); }
.donation-prompt a {
  color: var(--accent-primary);
  font-weight: 600;
  white-space: nowrap;
}
.donation-prompt a:hover,
.donation-prompt a:focus-visible {
  color: var(--accent-secondary);
  text-decoration: underline;
}

/* --------------------------------------------------------------------------
   14. Generator page
   -------------------------------------------------------------------------- */
.page-intro { text-align: center; margin-top: 2.5rem; margin-bottom: 2rem; }

/* Compact variant — smaller H1, no decorative flourish below the title.
   Used when the page already has its own loud visual hook (e.g. the
   Dragon Name Generator's parchment panel) and the page-intro should
   step back to a quieter introduction. */
.page-intro--compact h1 {
  font-size: clamp(1.5rem, 4vw, var(--text-3xl));
}

.page-intro .subtitle {
  color: var(--text-secondary);
  font-size: var(--text-lg);
  margin-top: 0.5rem;
  font-family: var(--font-subheading);
  font-style: italic;
}

/* (V1 generator block removed — `.generator-box`, `.name-display`,
   `.results-list`, `.generated-name`, `.gen-buttons`, `.select-control`
   were the original single-form generator UI from before the
   `.cn-generator` panel landed. None are present in any current HTML
   page. Removed Apr 2026.) */

/* --------------------------------------------------------------------------
   15. Content Sections (SEO blocks, FAQ)
   -------------------------------------------------------------------------- */
.content-section {
  background: var(--bg-card);
  border-radius: var(--radius-md);
  padding: 2rem 1.5rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-sm);
}

.content-section h2 {
  margin-bottom: 1.25rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--border-subtle);
  position: relative;
}
.content-section h2::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 80px;
  height: 2px;
  background: var(--accent-primary);
}

.content-section h3 {
  color: var(--accent-primary);
  margin-top: 1.5rem;
  margin-bottom: 0.5rem;
  font-family: var(--font-subheading);
  font-size: var(--text-lg);
  font-weight: 700;
}

.content-section ul {
  padding-left: 1.5rem;
  list-style: disc;
  color: var(--text-secondary);
  margin-bottom: 1rem;
}
.content-section ol {
  padding-left: 1.75rem;
  list-style: decimal;
  color: var(--text-secondary);
  margin-bottom: 1rem;
}
.content-section li { margin-bottom: 0.4rem; }

/* (.name-examples removed — was an article-side example grid no
   longer present in any HTML page.) */

/* (.tag-list removed — V1 keyword-pill component, not used.) */

/* FAQ */
.faq details {
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  padding: 14px 18px;
  margin-bottom: 10px;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.faq details[open] {
  border-color: var(--border-primary);
  background: #f9ecc8;
}
.faq summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--accent-primary);
  padding: 4px 0;
  font-family: var(--font-subheading);
  font-size: var(--text-base);
  list-style: none;
}
.faq summary::marker { display: none; }
.faq summary::before {
  content: "❧";
  display: inline-block;
  margin-right: 10px;
  color: var(--accent-gold);
  transition: transform var(--t-fast);
}
.faq details[open] summary::before { transform: rotate(90deg); }
.faq summary:hover { color: var(--accent-secondary); }
.faq details p {
  margin-top: 10px;
  margin-bottom: 0;
  color: var(--text-secondary);
  padding-left: 1.4rem;
}

.related-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 1rem;
}
.related-tools a { flex: 1 1 220px; }

/* --------------------------------------------------------------------------
   16. Ad slots
   -------------------------------------------------------------------------- */
.ad-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-secondary);
  border: 1px dashed var(--border-secondary);
  color: var(--text-light);
  font-size: 0.8rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  margin: 1.5rem auto;
  border-radius: var(--radius-sm);
}
.ad-slot--top { min-height: 50px; max-width: 728px; }
.ad-slot--side { width: 300px; height: 250px; max-width: 100%; margin: 1.5rem auto; }
.ad-slot--bottom { min-height: 90px; max-width: 728px; }

@media (min-width: 1024px) {
  .generator-layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 24px;
    align-items: start;
  }
  .ad-slot--side {
    margin: 0;
    position: sticky;
    top: 100px;
  }
  .ad-slot--top { min-height: 90px; }
}

/* --------------------------------------------------------------------------
   17. Toast
   -------------------------------------------------------------------------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(20px);
  background: var(--accent-primary);
  color: var(--text-white);
  padding: 12px 22px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-family: var(--font-body);
  box-shadow: var(--shadow-md);
  border: 1px solid var(--accent-gold);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base), transform var(--t-base);
  z-index: 1000;
  max-width: 90%;
  text-align: center;
}
.toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* --------------------------------------------------------------------------
   18. Footer (two-row layout)
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--bg-dark);
  color: var(--text-cream);
  padding: 2.5rem 0 1.75rem;
  margin-top: 3rem;
  border-top: 4px solid var(--accent-gold);
  position: relative;
  z-index: 1;
}

.footer-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1rem;
}

.footer-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: center;
  text-align: center;
}

.footer-row--main {
  justify-content: space-between;
}

.copyright {
  color: var(--text-cream);
  font-size: 0.9rem;
  font-family: var(--font-subheading);
  font-style: italic;
  margin: 0;
}

.footer-support {
  color: var(--text-cream);
  font-size: 0.9rem;
  margin: 0;
}
.footer-support .coffee-link {
  color: var(--accent-gold);
  font-weight: 600;
  white-space: nowrap;
  margin-left: 4px;
}
.footer-support .coffee-link:hover,
.footer-support .coffee-link:focus-visible {
  color: #f2c94c;
  text-decoration: underline;
}

.footer-links {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 20px;
  padding-top: 0.75rem;
  border-top: 1px solid rgba(212, 175, 55, 0.2);
}
.footer-links a {
  color: var(--text-cream);
  font-family: var(--font-body);
  font-size: 0.9rem;
  transition: color var(--t-fast);
}
.footer-links a:hover,
.footer-links a:focus-visible { color: var(--accent-gold); }

/* --------------------------------------------------------------------------
   19. Privacy / prose pages
   -------------------------------------------------------------------------- */
/* `.prose` panel shell is defined in the shared selector with
   `.cn-generator` (search for "Single source of truth"). Only
   `.prose`-internal rules (heading underlines, list styling, code
   blocks) live below. */

/* About page panel — same shell as Privacy's `.prose`; the modifier
   exists so small spacing tweaks (page-intro top margin, etc.) can
   be scoped without touching Privacy. */
.about-prose .page-intro {
  margin-top: 0;
}
.prose h2 {
  margin-top: 2rem;
  font-size: var(--text-2xl);
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border-subtle);
  position: relative;
}
.prose h2::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 60px;
  height: 2px;
  background: var(--accent-primary);
}
.prose p,
.prose li { color: var(--text-secondary); }
.prose ul {
  padding-left: 1.5rem;
  list-style: disc;
  margin-bottom: 1rem;
}
.prose li { margin-bottom: 0.4rem; }
.prose code {
  background: var(--bg-secondary);
  color: var(--accent-primary);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 0.9em;
  font-family: Menlo, Consolas, Monaco, monospace;
}

/* --------------------------------------------------------------------------
   20. Animations
   -------------------------------------------------------------------------- */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
}

/* --------------------------------------------------------------------------
   21. Responsive breakpoints
   -------------------------------------------------------------------------- */
/* ── Tablet+ (≥641px) — base tablet enhancements ─────────────────────── */
@media (min-width: 641px) {
  .container { padding: 0 32px; }
  main { padding: 3rem 0 4rem; }
  /* Tools grid: 1col → 2col at tablet. 3col moves up to desktop (1024px)
     so cards aren't tiny on portrait tablets / landscape phones. */
  .tools-grid { grid-template-columns: repeat(2, 1fr); }

  .footer-row {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    text-align: left;
  }
  .footer-links {
    justify-content: center;
  }
}

/* ── Desktop+ (≥1024px) — full multi-column layouts ──────────────────── */
@media (min-width: 1024px) {
  .container { padding: 0 40px; }
  .hero { padding: 4.5rem 0 3rem; }
  .tools-grid { grid-template-columns: repeat(3, 1fr); }
}

/* ── Mobile (≤640px) — compact overrides ─────────────────────────────────
   Mobile-first base styles handle most things; this block is a small set
   of *downward* tweaks for the chrome (header, full-width buttons) that
   would otherwise hog space on a 360px phone. Keep this list short. */
@media (max-width: 640px) {
  /* Header scrolls with content on mobile — only the ☰ button stays
     fixed in the top-right corner so it's always reachable.
     backdrop-filter MUST be removed: it creates a new containing block
     that traps position:fixed children (the ☰ button) inside the
     header instead of fixing them to the viewport. */
  .site-header {
    position: relative;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .nav-bar {
    padding: 12px 0;
    gap: 6px;
    flex-wrap: nowrap;
    justify-content: center; /* center brand (☰ is fixed, out of flow) */
  }
  .brand-name { font-size: 1.05rem; letter-spacing: 1.4px; }

  /* Show the hamburger button — FIXED to the viewport top-right so it
     stays visible no matter how far the user scrolls or zooms. */
  .nav-toggle {
    display: inline-flex;
    position: fixed;
    top: 12px;
    right: 12px;             /* equal spacing from top and right edges */
    z-index: 1000;
    background: var(--bg-primary);
    box-shadow: 0 2px 8px rgba(45, 27, 0, 0.12);
  }

  /* Dropdown overlay — also fixed, appears below the ☰ button.
     Full viewport width, overlays page content. */
  .nav-bar > nav {
    display: none;
    position: fixed;
    top: 52px;               /* below the fixed ☰ button */
    left: 0;
    right: 0;
    background: var(--bg-primary);
    border-bottom: 2px solid var(--border-primary);
    box-shadow: 0 4px 16px rgba(45, 27, 0, 0.15);
    z-index: 999;
    padding: 0 16px;
  }
  .nav-bar[data-nav-open="true"] > nav { display: block; }

  /* Stack nav items vertically, centered text. */
  .nav-bar[data-nav-open="true"] .nav-list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 0;
  }
  .nav-bar[data-nav-open="true"] .nav-list li {
    list-style: none;
  }
  .nav-bar[data-nav-open="true"] .nav-list a {
    display: block;
    padding: 14px 8px;       /* ~48px tap targets */
    font-size: 1.05rem;
    border-radius: 6px;
    text-align: center;
  }
  .nav-bar[data-nav-open="true"] .nav-list a:hover,
  .nav-bar[data-nav-open="true"] .nav-list a:focus-visible {
    background: var(--bg-secondary);
    text-decoration: underline;
    text-underline-offset: 4px;
    text-decoration-thickness: 2px;
    text-decoration-color: var(--accent-primary);
  }
  /* Theme toggle's <li> — move to FIRST position in the dropdown.
     order applies to the <li> (the direct flex child of .nav-list). */
  .nav-bar .nav-list li:last-child {
    order: -1;
  }
  /* Theme toggle button — center-aligned to match the nav links. */
  .nav-bar .theme-toggle {
    width: 100%;
    text-align: center;
    padding: 14px 8px;
    border-radius: 6px;
    background: transparent;
    border: none;
    font-size: 1.05rem;
    cursor: pointer;
    transition: background var(--t-fast), color var(--t-fast);
    transform: none;         /* override desktop rotate on hover */
  }
  .nav-bar .theme-toggle:hover,
  .nav-bar .theme-toggle:focus-visible {
    background: var(--bg-secondary);
    transform: none;
  }

  /* No sticky header on mobile → no scroll-padding offset needed. */
  html { scroll-padding-top: 16px; }

  /* Hide the brand tagline if it's ever re-introduced (graceful no-op
     today since no .brand-tagline element exists). */
  .brand-tagline { display: none; }

  /* Full-width CTAs on mobile — easier thumb target. */
  .btn-lg { width: 100%; }
}

/* ==========================================================================
   22. Recent Creations panel — shared by every generator.
   The dragon and character pages both render their generator UI via
   `.cn-generator` (see section 23) but the Recent panel lives outside
   that scope so this is its single home.
   ========================================================================== */

/* Recent Names */
.recent-names-section {
  padding: 20px;
  background: rgba(249, 243, 232, 0.5);
  border-radius: 12px;
  border: 1px solid var(--border-subtle);
}

.recent-names-section h3 {
  font-family: var(--font-heading);
  color: var(--accent-primary);
  margin: 0;                    /* spacing is owned by .recent-names-header */
  font-size: 20px;
}

/* Header row: section title on the left, "Copy All" button on the right.
   Shared by both generators — same markup + same CSS. */
.recent-names-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.recent-list {
  list-style: none;
  padding: 0 6px 0 0;      /* reserve room for scrollbar so text doesn't shift */
  margin: 0;
  /* Scrolling panel — holds up to 100 entries without bloating page height.
     Shared by both generators: dragon + character use the same .recent-list. */
  max-height: 480px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--accent-gold) transparent;
}
.recent-list::-webkit-scrollbar        { width: 8px; }
.recent-list::-webkit-scrollbar-track  { background: transparent; }
.recent-list::-webkit-scrollbar-thumb  {
  background: var(--accent-gold);
  border-radius: 4px;
}

.recent-list:empty::after {
  content: "Your recent names will appear here.";
  display: block;
  color: var(--text-light);
  font-style: italic;
  font-family: var(--font-subheading);
  font-size: 14px;
  padding: 8px 0;
}

.recent-name-item {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  margin-bottom: 8px;
  background: white;
  border-radius: 8px;
  border-left: 4px solid var(--accent-gold);
  transition: transform var(--t-base), box-shadow var(--t-base);
}

.recent-name-item:last-child {
  margin-bottom: 0;
}

.recent-name-item:hover {
  transform: translateX(4px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.recent-name-item .name {
  font-weight: 700;
  color: var(--accent-primary);
  /* Per RULES.md R-TYPO-001: match the form-label font. */
  font-family: var(--font-heading);
}

.recent-name-item .subtitle {
  font-family: var(--font-subheading);
  font-size: 0.75em;
  font-style: italic;
  font-weight: 400;
  color: var(--text-secondary);
  opacity: 0.8;
  margin-left: 4px;
}

.recent-name-item .epithet {
  font-style: italic;
  color: var(--text-secondary);
  margin-left: 4px;
}

/* Unified Copy button — pill shape used by:
     • every row in Recent Creations  (.recent-name-item .copy-btn)
     • the "Copy All" button in the Recent Creations header
   (Generated-name cards no longer have an inner Copy button — the
   whole card IS the button now. See `.cn-card { cursor: pointer; }`.)
   Keeping these in one grouped selector is the whole point of the
   "standardise" pass — edit here, every surface updates. */
.recent-name-item .copy-btn,
.recent-copy-all-btn {
  flex: 0 0 auto;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--accent-primary);
  padding: 6px 12px;
  border: 1px solid rgba(139, 38, 53, 0.35);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.6);
  cursor: pointer;
  transition: background 0.15s ease-out,
              border-color 0.15s ease-out,
              color 0.15s ease-out,
              opacity 0.15s ease-out;
}

/* Row buttons sit at the right of each row; start slightly faded until
   hovered so the name (not the action) is what the eye catches. */
.recent-name-item .copy-btn {
  margin-left: auto;
  opacity: 0.7;
}

.recent-name-item .copy-btn:hover,
.recent-name-item .copy-btn:focus-visible,
.recent-copy-all-btn:hover,
.recent-copy-all-btn:focus-visible {
  opacity: 1;
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: #fff;
  outline: none;
}

.recent-copy-all-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  pointer-events: none;
}

/* Toast Notification (V2) */
.toast-notification {
  position: fixed;
  bottom: 30px;
  left: 50%;
  transform: translate(-50%, 20px);
  background: var(--accent-primary);
  color: white;
  padding: 14px 28px;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  z-index: 9999;
  font-weight: 600;
  font-family: var(--font-body);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base), transform var(--t-base);
  border: 1px solid var(--accent-gold);
  max-width: 90%;
  text-align: center;
}

.toast-notification.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* (@keyframes fadeInScale, slideUp, popIn removed — orphaned from V1
   generator UI. The site now uses fadeIn / cnFadeIn / cnLegendPulse /
   cnLegendShimmer for animations.) */

/* SEO content container — inherits .content-section look via double-class. */
.seo-content h3 {
  color: var(--accent-primary);
  font-family: var(--font-subheading);
  font-size: var(--text-lg);
  margin-top: 1.5rem;
  margin-bottom: 0.4rem;
  font-weight: 700;
}

.seo-content ul,
.seo-content ol {
  padding-left: 1.5rem;
  color: var(--text-secondary);
  margin-bottom: 1rem;
}

.seo-content ul { list-style: disc; }
.seo-content ol { list-style: decimal; padding-left: 1.75rem; }

/* Inline "coming soon" tag used next to placeholder links in Related Tools
   sections. Muted, smaller, low-opacity so the link still reads as one
   phrase but the status is obvious. */
.coming-soon-tag {
  display: inline-block;
  margin-left: 6px;
  font-size: 0.75em;
  font-weight: 500;
  font-style: italic;
  letter-spacing: 0.3px;
  opacity: 0.65;
  text-transform: lowercase;
}

/* ==========================================================================
   Character Name Generator (角色取名生成器)

   All rules live under .cn-generator and use a locally-scoped palette of
   CSS custom properties. The site-wide theme toggle owns light/dark —
   the dark palette fires under `html.theme-dark .cn-generator` (see
   below). The legacy `.cn-theme-dark` section-class is still accepted
   as an alias.

   Class prefix `.cn-*` stands for "character name" (the generator is
   culture-pluggable; Chinese is the first implementation).
   ========================================================================== */

/* ★ Single source of truth for "the visible main panel on a page".
   Both the generator panels (`.cn-generator`) and the article panels
   (`.prose`) read from the same `--panel-*` tokens, so all pages
   render the same panel — same width, same color, same padding,
   same border, same radius. Tweak a token in :root and every page
   updates from one edit.

   Dark mode swap is automatic via the dark-mode token block. */
.cn-generator,
.prose {
  max-width: var(--w-main);
  margin: 24px auto 48px;
  padding: var(--panel-padding);
  background: var(--panel-bg);
  color: var(--panel-text);
  border: 1px solid var(--panel-border);
  border-radius: var(--panel-radius);
  transition: background 0.25s ease,
              color 0.25s ease,
              border-color 0.25s ease;
}

/* Generator-specific tokens — only the inner card and badge styles
   inside `.cn-generator` consume these. They DON'T paint the panel
   shell anymore (that's the shared rule above). Adding a new
   non-panel generator inside `.cn-generator` should reach for these
   for surface / accent / shadow values. */
.cn-generator {
  --cn-bg:          var(--panel-bg);
  --cn-surface:     #ffffff;
  --cn-surface-2:   #fbf5ea;
  --cn-text:        var(--panel-text);
  --cn-text-muted:  #8a7a6a;
  --cn-border:      var(--panel-border);
  --cn-accent:      #8b2635;
  --cn-legend:      #d4af37;
  --cn-legend-soft: #fff5c6;
  --cn-legend-glow: rgba(212, 175, 55, 0.55);
  --cn-shadow:      0 4px 16px rgba(58, 45, 36, 0.08);

  /* CJK-friendly font stack — relies on system-installed fonts so we
     don't have to ship Noto Serif SC (huge) as a webfont. */
  --cn-font-cjk: 'Noto Serif SC', 'Source Han Serif SC', 'PingFang SC',
                 'Hiragino Sans GB', 'Microsoft YaHei', SimSun, serif;
}

/* Dark palette kicks in whenever the site-wide theme is dark.
   The old per-page `.cn-theme-dark` class is retained below as an
   alias for backwards-compatibility with any cached HTML that still
   carries it, but new markup relies on the site-wide toggle. */
html.theme-dark .cn-generator,
.cn-generator.cn-theme-dark {
  --cn-bg:          #0f0d0b;
  --cn-surface:     #1a1613;
  --cn-surface-2:   #221c18;
  --cn-text:        #f5ecd8;
  --cn-text-muted:  #a89680;
  --cn-border:      rgba(212, 175, 55, 0.28);
  --cn-accent:      #e85866;
  --cn-legend:      #f5cc4a;
  --cn-legend-soft: #fff5c6;
  --cn-legend-glow: rgba(245, 204, 74, 0.45);
  --cn-shadow:      0 4px 24px rgba(0, 0, 0, 0.45);
}

/* Header ---------------------------------------------------------------- */
.cn-gen-header {
  text-align: center;
  margin-bottom: 20px;
}

.cn-gen-title {
  font-family: var(--cn-font-cjk);
  font-size: 28px;
  font-weight: 700;
  letter-spacing: 2px;
  color: var(--cn-accent);
  margin: 0 0 6px;
}

.cn-gen-subtitle {
  font-family: var(--font-subheading), 'Lora', serif;
  font-style: italic;
  font-size: 14px;
  color: var(--cn-text-muted);
  margin: 0;
}

/* Controls -------------------------------------------------------------- */
.cn-gen-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.cn-culture-wrap {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.cn-culture-label {
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--cn-text-muted);
}

.cn-culture-select {
  font-family: var(--cn-font-cjk);
  font-size: 11px;
  padding: 6px 10px;
  background: var(--cn-surface);
  color: var(--cn-text);
  border: 1px solid var(--cn-border);
  border-radius: 6px;
  cursor: pointer;
  min-width: 144px;
}

.cn-culture-select:focus-visible {
  outline: 2px solid var(--cn-legend);
  outline-offset: 2px;
}

/* Generate button — Royal Obsidian shape, shared across both themes.
   Sharp 2px corners, 1.5px gold metallic-gradient border (via
   border-image), uppercase letter-spaced label, ambient gold glow.
   Surface fill / text color / glow color come from --btn-generate-*
   tokens so light + dark only differ in palette. */
.cn-generate-btn {
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 700;
  padding: 11px 24px;
  background: var(--btn-generate-bg);
  color: var(--btn-generate-color);
  border: 1.5px solid var(--accent-gold);
  border-image: linear-gradient(135deg,
    var(--accent-gold) 0%,
    var(--accent-gold-highlight) 50%,
    var(--accent-gold) 100%) 1 stretch;
  border-radius: 2px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  cursor: pointer;
  text-shadow: var(--btn-generate-text-shadow);
  box-shadow:
    0 0 15px var(--btn-generate-glow),
    inset 0 0 0 1px rgba(0, 0, 0, 0.06);
  transition: background 0.2s ease,
              color 0.2s ease,
              box-shadow 0.25s ease,
              transform 0.12s ease;
}

.cn-generate-btn:hover {
  background: var(--btn-generate-bg-hover);
  color: var(--btn-generate-color-hover);
  text-shadow: none;
  box-shadow:
    0 0 28px var(--btn-generate-glow-hover),
    inset 0 0 0 1px rgba(0, 0, 0, 0.15);
  transform: translateY(-1px);
}

.cn-generate-btn:active { transform: translateY(0); }

.cn-theme-toggle {
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 12px;
  font-weight: 600;
  padding: 10px 16px;
  background: transparent;
  color: var(--cn-text);
  border: 1px solid var(--cn-border);
  border-radius: 999px;
  cursor: pointer;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.cn-theme-toggle:hover {
  border-color: var(--cn-legend);
  color: var(--cn-legend);
}

/* Announce line -------------------------------------------------------- */
.cn-announce {
  min-height: 18px;
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 12px;
  text-align: center;
  color: var(--cn-text-muted);
  letter-spacing: 0.3px;
  margin-bottom: 14px;
}

/* Results grid --------------------------------------------------------- */
.cn-results-grid {
  list-style: none;
  padding: 0;
  margin: 0 0 13px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 13px;
}

/* Single-column variant — for generators whose card content is dense
   (long Latin names plus epithet flavor lines, e.g. the Dragon
   generator). Each card occupies its own full-width row instead of
   sharing horizontal space, so "Name, the Epithet" reads on one line
   without competing with a sibling card. */
.cn-results-grid--wide {
  grid-template-columns: 1fr;
}

/* In the wide variant we lay the card out as a horizontal row:
   text-stack on the left, Copy pill on the right. The `.cn-card-text`
   wrapper graduates from `display: contents` (default) to a real flex
   column, and `.cn-card-inner` flips from column to row.

   This is also where the Royal Obsidian card frame lives — sharp 2px
   corners, 1px subtle border, L-shaped gold corner accents, all using
   tokens (--card-wide-bg / --card-wide-border / --card-wide-shadow)
   so light mode reads parchment-and-gold and dark mode reads
   obsidian-and-gold from the SAME structural rule. */
.cn-results-grid--wide .cn-card {
  background: var(--card-wide-bg);
  border: 1px solid var(--card-wide-border);
  border-radius: 2px;
  box-shadow: var(--card-wide-shadow);
}
.cn-results-grid--wide .cn-card::before,
.cn-results-grid--wide .cn-card::after {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--accent-gold);
  pointer-events: none;
  z-index: 2;
  transition: border-color 0.2s ease;
}
.cn-results-grid--wide .cn-card::before {
  top: -2px;
  left: -2px;
  border-right: 0;
  border-bottom: 0;
}
.cn-results-grid--wide .cn-card::after {
  bottom: -2px;
  right: -2px;
  border-left: 0;
  border-top: 0;
}
.cn-results-grid--wide .cn-card:hover::before,
.cn-results-grid--wide .cn-card:hover::after {
  border-color: var(--accent-gold-highlight);
}

.cn-results-grid--wide .cn-card-inner {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 13px;
  text-align: left;
  min-height: var(--card-min-height-wide);
  padding: 13px 16px;
}
.cn-results-grid--wide .cn-card-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  flex: 1 1 auto;
  min-width: 0;
}
.cn-results-grid--wide .cn-card-headline,
.cn-results-grid--wide .cn-card-name,
.cn-results-grid--wide .cn-card-pinyin {
  text-align: left;
}

/* Hero typography — Cinzel Bold 700 ahead of the CJK fallback so Latin
   glyphs render in the monumental Roman face and Hanzi falls through
   to the CJK serif stack. 2.125rem (~34px) for headline presence in
   both modes; the only thing that swaps per theme is the text color. */
.cn-results-grid--wide .cn-card-name {
  font-family: 'Cinzel', var(--cn-font-cjk);
  font-weight: 700;
  font-size: 1.7rem;
  letter-spacing: 1.6px;
  line-height: 1.15;
  text-shadow: 0 0 16px var(--halo-h1);
}
@media (max-width: 640px) {
  .cn-results-grid--wide .cn-card-name {
    font-size: 1.2rem;
    letter-spacing: 1px;
  }
}

.cn-results-grid--wide .cn-card-pinyin {
  margin-top: 2px;
}
.cn-results-grid--wide .cn-card-epithet {
  color: var(--epithet-color);
  opacity: 0.95;
}
/* (.cn-card-copy removed — the whole card is now the button.) */

@keyframes cnFadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Card shell — shared between base and legend -------------------------- */
.cn-card {
  position: relative;           /* container for badge absolute positioning */
  background: var(--cn-surface);
  border: 1px solid var(--cn-border);
  border-radius: 11px;
  box-shadow: var(--cn-shadow);
  transition: transform 0.15s ease, box-shadow 0.2s ease;
}

.cn-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(58, 45, 36, 0.14);
}

html.theme-dark .cn-card:hover,
.cn-theme-dark .cn-card:hover {
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.55);
}

.cn-card-inner {
  position: relative;
  overflow: hidden;             /* clips the legend shimmer */
  border-radius: 10px;
  padding: 18px 13px 13px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  /* ★ Standard card size — locks every gacha-grid card at the same
     height regardless of whether the name has pinyin, an epithet, or
     stands bare. Token defined in :root. */
  min-height: var(--card-min-height-grid);
}

/* Optional text-stack wrapper (name + pinyin + epithet). Only the Dragon
   generator emits this; when present it lets the wide-grid variant lay
   the card out as a horizontal row — see `.cn-results-grid--wide`. In
   the default (square) grid this is a transparent passthrough that
   inherits the parent's column alignment. */
.cn-card-text {
  display: contents;
}

.cn-card-name {
  font-family: var(--cn-font-cjk);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 1.6px;
  color: var(--cn-text);
  line-height: 1.2;
  text-align: center;
  word-break: break-word;
}

/* Hanyu Pinyin subtitle — small, italic, muted so it reads as a guide
   under the Hanzi without competing with the name itself. Sits between
   .cn-card-name and the Copy button inside .cn-card-inner. */
.cn-card-pinyin {
  font-family: var(--font-subheading), 'Lora', Georgia, serif;
  font-size: 11px;
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0.3px;
  line-height: 1.3;
  text-align: center;
  color: var(--cn-text-muted);
  margin-top: -2px;
  word-break: break-word;
}

.cn-card--legend .cn-card-pinyin {
  color: var(--cn-legend);
  opacity: 0.85;
}

/* Headline wrapper — keeps name + epithet on one typographic line.
   Block-level so it occupies its own row inside `.cn-card-text`; inside
   it, both name and epithet are inline by default so they flow as a
   single phrase ("Hrafnarax, Scourge of the Jade Caverns"). Centered by
   default to match the square-grid card aesthetic; the wide-grid
   variant flips this to left-align. */
.cn-card-headline {
  display: block;
  line-height: 1.25;
  text-align: center;
}

/* Epithet — appended inline after the name with a leading ", ".
   Italic + muted to read as flavor text without competing with the
   name itself. Only the Dragon generator emits this slot today.
   Absolute font-size keeps it readable regardless of the surrounding
   context; the visual hierarchy (name dominant, epithet secondary)
   comes from the size gap to .cn-card-name (28px default / 22px wide). */
.cn-card-epithet {
  display: inline;
  font-family: var(--font-subheading), 'Lora', Georgia, serif;
  font-size: 14px;
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0.2px;
  color: var(--cn-accent);
  opacity: 0.85;
  word-break: break-word;
}

.cn-card--legend .cn-card-epithet {
  color: var(--cn-legend);
  opacity: 0.95;
}

.cn-card-meta {
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 9px;
  font-weight: 500;
  color: var(--cn-text-muted);
  letter-spacing: 0.8px;
  text-align: center;
}

/* The card itself is now the click target — no inner Copy button.
   role="button" + tabindex="0" on the <li> turn it into an accessible
   button; we just need cursor + focus-visible styling here.

   :active gives a tiny press-down feedback. :focus-visible draws a
   gold outline so keyboard users can see which card has focus. */
.cn-card {
  cursor: pointer;
}
.cn-card:active {
  transform: scale(0.995);
}
.cn-card:focus-visible {
  outline: 2px solid var(--accent-gold-highlight);
  outline-offset: 3px;
}

/* Legend treatment — gold border, glow, shimmer, badge ----------------- */
.cn-card--legend .cn-card-name {
  color: var(--cn-legend);
  text-shadow: 0 0 12px var(--cn-legend-glow);
}

/* Gold gradient border via the double-background trick:
   inner gradient = solid surface, outer gradient = gold, borders render
   as the difference. Needs `border: 2px solid transparent`. */
.cn-card--legend {
  border: 2px solid transparent;
  background-clip: padding-box, border-box;
  background-origin: border-box;
  background-image:
    linear-gradient(var(--cn-surface), var(--cn-surface)),
    linear-gradient(135deg,
      var(--cn-legend) 0%,
      var(--cn-legend-soft) 50%,
      var(--cn-legend) 100%);
  animation: cnLegendPulse 3s ease-in-out infinite;
}

@keyframes cnLegendPulse {
  0%, 100% { box-shadow: 0 4px 16px var(--cn-legend-glow); }
  50%      { box-shadow: 0 6px 28px var(--cn-legend-glow); }
}

/* Shimmer sweep — lives on .cn-card-inner because that's where we clip. */
.cn-card--legend .cn-card-inner::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 30%,
    rgba(255, 245, 198, 0.28) 50%,
    transparent 70%
  );
  transform: translateX(-120%);
  pointer-events: none;
  animation: cnLegendShimmer 4.5s ease-in-out infinite;
}

@keyframes cnLegendShimmer {
  0%   { transform: translateX(-120%); }
  55%  { transform: translateX(120%); }
  100% { transform: translateX(120%); }
}

/* Legendary badge — peeks above the card's top-right corner. */
.cn-card-badge {
  position: absolute;
  top: -8px;
  right: 10px;
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  background: linear-gradient(135deg,
    var(--cn-legend) 0%,
    var(--cn-legend-soft) 100%);
  color: #2a1f11;
  box-shadow: 0 2px 10px var(--cn-legend-glow);
  z-index: 2;
  white-space: nowrap;
}

/* Hint line ------------------------------------------------------------ */
.cn-hint {
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 12px;
  color: var(--cn-text-muted);
  text-align: center;
  margin: 12px 0 0;
}

.cn-hint kbd {
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 5px;
  background: var(--cn-surface-2);
  border: 1px solid var(--cn-border);
  color: var(--cn-text);
}

/* Toast --------------------------------------------------------------- */
.cn-toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(60px);
  padding: 12px 22px;
  background: #8b2635;
  color: #fff8e6;
  font-family: var(--font-body), Inter, sans-serif;
  font-size: 14px;
  border-radius: 999px;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.22);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.25s ease, opacity 0.2s ease;
  z-index: 9999;
}
.cn-toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Responsive ---------------------------------------------------------- */
@media (max-width: 640px) {
  .cn-generator       { padding: 24px 16px; }
  .cn-gen-title       { font-size: 24px; }
  .cn-card-name       { font-size: 19px; letter-spacing: 0.8px; }
  .cn-card-inner      { min-height: 88px; padding: 14px 10px 11px; }
  .cn-results-grid    { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 10px; }
  /* .cn-results-grid--wide stays 1fr (single column) at every breakpoint. */
  .cn-generate-btn    { font-size: 12px; padding: 10px 18px; letter-spacing: 1px; }
  .cn-culture-select  { min-width: 112px; }
}

/* ==========================================================================
   22b. Dark-theme overrides for rules that hardcode parchment whites /
        light gradients instead of using the --bg-* tokens.

   These rules existed before the site-wide theme toggle landed; rewriting
   them to use tokens everywhere would be a bigger refactor, so we patch
   the specific colors under `html.theme-dark` here. Order matches the
   source section they override.
   ========================================================================== */

/* FAQ open-state (section 15): cream highlight → warm near-black. */
html.theme-dark .faq details[open] {
  background: #2a2016;
}

/* Recent Creations panel — dark surface for both generators. */
html.theme-dark .recent-names-section {
  background: rgba(255, 255, 255, 0.02);
}
html.theme-dark .recent-name-item {
  background: #1e1813;
}
html.theme-dark .recent-name-item:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
}
/* Dark-theme pill — translucent surface + gold-cast border, solid
   accent on hover. Used by both Recent Creations row buttons and the
   "Copy All" button in the Recent Creations header. */
html.theme-dark .recent-name-item .copy-btn,
html.theme-dark .recent-copy-all-btn {
  background: rgba(255, 255, 255, 0.05);
  color: var(--accent-gold);
  border-color: rgba(212, 175, 55, 0.45);
}
html.theme-dark .recent-name-item .copy-btn:hover,
html.theme-dark .recent-name-item .copy-btn:focus-visible,
html.theme-dark .recent-copy-all-btn:hover,
html.theme-dark .recent-copy-all-btn:focus-visible {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: #fff;
}

/* Sticky footer keeps its dark brown in light mode and a near-black in
   dark — the `--bg-dark` token handles it automatically. Nothing extra
   needed here. */
