/* ================================================
   NO DICE — SHARED STYLESHEET (styles.css)
   Loaded by every page via <link rel="stylesheet">
   ================================================

   CONSOLIDATED CSS ARCHITECTURE
   ─────────────────────────────────────────
   
   This stylesheet contains ALL styles for the application,
   organized into SHARED and PAGE-SPECIFIC sections:

   SHARED STYLES (Sections 1–13):
   ├─ CSS Variables (:root)         — All color tokens
   ├─ Box-sizing reset
   ├─ Body base + parchment background
   ├─ Header typography (.site-label, h1 span)
   ├─ Footer + nav link (.nav-link)
   ├─ Divider
   ├─ Source badge + live/fallback dot
   ├─ Loading spinner (.loading, .spinner)
   ├─ Primary buttons (.btn-primary, .roll-btn, .pull-btn)
   ├─ Card footer base (.card-footer)
   ├─ Lock notice (chargen + traitgen only)
   ├─ Mulligan bar + pips (chargen + traitgen only)
   └─ Shared animations (@keyframes cardIn, spin, slideUp)

   THEME SYSTEM (3 themes):
   ├─ Light Theme (default :root values)
   ├─ Dark Theme (html[data-theme="dark"])
   └─ No Dice Theme (html[data-theme="nodice"])

   PAGE-SPECIFIC STYLES (Sections 14–21):
   ├─ Index/Hub Page
   ├─ Chargen Page
   ├─ Coinflip Page
   ├─ Loot Page
   ├─ Poll Page (includes Admin Panel)
   ├─ QR Code Page
   ├─ Traitgen Page
   └─ Profile Page

   ANIMATION NAMING CONVENTION:
   ────────────────────────────
   Page-specific animations are prefixed with the page name:
   • chargen-spin (from generic "spin")
   • coinflip-coinFlip, coinflip-wobble, coinflip-slideUp
   • traitgen-spin (from generic "spin")
   
   This prevents unintended style leakage between pages.

   HOW TO USE THIS FILE:
   ─────────────────────
   1. To edit shared styles: modify Sections 1–13
   2. To add a new tool: create new PAGE-SPECIFIC section
   3. To adjust colors: edit :root in Section 1
   4. NEVER hardcode hex values — use CSS variables
   5. Dev-only styles are marked /* DEV ONLY */ comments
   6. Theme overrides are in dedicated sections at the end

   ================================================ */


/* ================================================
   PAGE-SPECIFIC STYLES
   ================================================ */

/* ════════════════════════════════════════════════════════════════════════════════
   ⚠️  CRITICAL: PAGE-SPECIFIC BODY/HTML SELECTORS
   
   PROBLEM: Each tool page has conflicting body/html styles. When consolidated into
   a single stylesheet, only the LAST definition applies globally - breaking layouts.
   
   SOLUTION: Use page-specific classes (.chargen-page, .coinflip-page, etc.) to
   scope body styles to their respective pages. These classes are added to <body> 
   tags in each HTML file.
   
   CONVENTION: For any future styles targeting the body element on a specific page:
   Use: body.<page-name>-page { ... }  ← body element WITH the class (correct)
   NOT: .<page-name>-page body { ... } ← body INSIDE an element (wrong — body has no parent)

   EXAMPLE: body.chargen-page { display: flex; } applies only to chargen.html
            body.coinflip-page { display: flex; } applies only to coinflip.html

   DO NOT use bare selectors like "body { }" in page sections - it breaks other pages!
   ════════════════════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════════════════════
   🛑 THREE BUGS FIXED (April 2026) — READ BEFORE EDITING BODY/MAIN SELECTORS

   ── BUG 1: Wrong body selector syntax ──────────────────────────────────────────
   BROKEN:  .index-page body { }   → "body INSIDE .index-page" — never matches
   CORRECT: body.index-page { }    → "body element WITH class index-page" ✓
   Same rule for ALL page classes. The space makes all the difference.

   SYMPTOM: Body styles silently ignored → no flex layout → shelf widths driven
   by content → variable-width misaligned shelves on index.html.

   SCAN FOR THIS:  grep -n "\.\(chargen\|loot\|poll\|qrcode\|traitgen\|profile\|index\|coinflip\)-page body" styles.css
   Expected result: ONLY matches inside comments, never as live selectors.

   ── BUG 2: Bare main{} selectors bleeding across pages ─────────────────────────
   Each page section had an unscoped "main { }" rule. The last one wins (cascade),
   but EARLIER ones set align-items/justify-content that later rules don't reset.
   Coinflip's "main { align-items:center; justify-content:center; }" was vertically
   centering index.html's shelf list.

   FIX: index.html's main selector is now ".page-wrap > main { align-items:stretch;
   justify-content:flex-start; }" — explicit resets plus a scoped selector.

   SCAN FOR THIS:  grep -n "^  main\s*{" styles.css
   Any match should be reviewed — prefer scoped selectors like .page-wrap > main.

   ── BUG 3: Flex on body with align-items:center shrinks children ───────────────
   index.html body had "display:flex; align-items:center" (cross-axis centering).
   In a flex-column container, this lets children shrink to content width instead
   of stretching. Looked fine on wide screens, broke on narrow ones.

   FIX: Removed flex from body.index-page entirely. Used block-centering instead:
   .page-wrap { max-width:480px; margin:0 auto; } — same pattern profile.html uses.

   ════════════════════════════════════════════════════════════════════════════════ */

/* Page-specific body layout — CORRECT form: body.PAGE-page { }
   The html{height:100%} lines from the old pattern are dropped: 100dvh units
   make them unnecessary, and they couldn't be page-scoped anyway. */
body.chargen-page {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}

body.coinflip-page {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
}

body.loot-page {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}

body.poll-page {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

body.bosscontrol-page {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

body.qrcode-page {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

body.traitgen-page {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}

body.profile-page {
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
}

/* ─────────────────────────────────────────
   CHARGEN PAGE
   Character Generator: Roll a character with
   name, race, class, backstory, quirk, secret.
   Features: Field reroll, mulligan system, lockout.
   ───────────────────────────────────────── */

  /* ⚠️  PAGE-SPECIFIC: All styles in this section are scoped to .chargen-page */
  /* DO NOT use bare body/html/header/main selectors - use .chargen-page <selector> */

  /* ── Page layout (body.chargen-page defined in global page-body block above) ── */

  /* ── Desktop wrapper — .page-frame base + media query come from styles.css ── */
  @media (min-width: 600px) {
    .page-frame { max-height: 860px; }
  }

  /* ── Header ── */
  /* .site-label, header h1, .subtitle come from styles.css */
  header {
    text-align: center;
    padding: 10px 16px 6px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    position: relative;
    background-color: var(--parchment);
  }

  /* .mulligan-bar, .pip-row, .pip, .pip.spent come from styles.css */

  /* ── Main scrollable area ── */
  #app {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 0 12px 6px;
    min-height: 0;
    background-color: var(--parchment);
  }

  /* .loading + .loading .spinner come from styles.css */

  /* ── Single white card that holds everything ── */
  .character-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: 0 4px 24px var(--shadow);
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
    animation: cardIn .45s cubic-bezier(.22,1,.36,1) both;
  }

  /* Scrollable field area inside the card */
  .fields-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
  }

  .fields-scroll::-webkit-scrollbar { width: 4px; }
  .fields-scroll::-webkit-scrollbar-track { background: transparent; }
  .fields-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

  /* ── Each field row inside the card ── */
  .field-row {
    display: flex;
    align-items: flex-start;
    padding: 0 14px;
    min-height: 52px;
    position: relative;
  }

  .field-row:nth-child(even) {
    background: rgba(201,168,76,.03);
  }

  .field-row + .field-row::before {
    content: '';
    position: absolute;
    top: 0; left: 14px; right: 14px;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--border) 20%, var(--border) 80%, transparent);
  }

  .field-text {
    flex: 1;
    min-width: 0;
    padding: 7px 0;
  }

  .field-label {
    font-family: 'Cinzel', serif;
    font-size: 0.68rem;
    font-weight: 700;
    color: var(--gold);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    line-height: 1;
    margin-bottom: 3px;
  }

  .field-value {
    font-size: 0.92rem;
    font-weight: 400;
    line-height: 1.3;
    color: var(--ink);
    transition: opacity 0.15s;
  }

  .field-value.fading { opacity: 0; }

  /* ── Reroll button ── */
  .reroll-btn {
    flex-shrink: 0;
    margin-left: 10px;
    margin-top: 18px;
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 4px 8px;
    font-family: 'Lato', sans-serif;
    font-size: 0.65rem;
    font-weight: 700;
    color: var(--muted);
    cursor: pointer;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    transition: border-color 0.2s, color 0.2s, background 0.2s;
    display: flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
  }

  .reroll-btn:hover:not(:disabled) {
    border-color: var(--gold);
    color: var(--gold);
    background: var(--gold-bg);
  }

  .reroll-btn:disabled { opacity: 0.35; cursor: not-allowed; }
  .reroll-btn .die { font-size: 0.82rem; }

  /* .card-footer comes from styles.css */
  /* .roll-btn, .roll-btn:hover, :active, :disabled come from styles.css */
  /* .lock-notice + children come from styles.css */
  /* .source-badge + .dot + .live/.fallback come from styles.css */

  /* ── Footer nav ── */
  /* .nav-link comes from styles.css */
  footer {
    text-align: center;
    padding: 5px 0 7px;
    flex-shrink: 0;
    background-color: var(--parchment);
  }

  /* ── Dev reset button ── */
  .reset-btn {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    background: none;
    border: 1px solid #c0392b;
    border-radius: 5px;
    padding: 3px 8px;
    font-family: 'Lato', sans-serif;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #c0392b;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.2s;
  }
  .reset-btn:hover { opacity: 1; }

  /* @keyframes cardIn and @keyframes spin come from styles.css */
  .die.spinning { animation: spin 0.35s ease; }


/* ─────────────────────────────────────────
   COINFLIP PAGE
   Fate's Flip: Flip a coin for pass/fail results.
   Features: Spinning animation, result reveal, wobble.
   ───────────────────────────────────────── */

  /* ⚠️  PAGE-SPECIFIC: All styles in this section are scoped to .coinflip-page */
  /* DO NOT use bare body/html/header/main selectors - use .coinflip-page <selector> */

    /* ── Page layout ── */
    body {
      min-height: 100dvh;
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    /* .site-label comes from styles.css */
    header {
      width: 100%;
      max-width: 420px;
      padding: 2rem 1.5rem .75rem;
      text-align: center;
    }

    /* Base header h1 styles come from styles.css — override size only */
    header h1 {
      font-size: 1.75rem;
      line-height: 1.15;
    }

    /* h1 span gold colour comes from styles.css */

    /* .subtitle base comes from styles.css */
    .subtitle {
      margin-top: .4rem;
      font-size: .85rem;
      font-weight: 300;
      color: var(--muted);
      letter-spacing: .03em;
    }

    /* Width override — gradient + height come from styles.css .divider */
    .divider { width: 80px; }

    main {
      width: 100%;
      max-width: 420px;
      padding: 0 1.25rem 2rem;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 1.25rem;
    }

    .card {
      width: 100%;
      background: var(--card-bg);
      border: 1px solid var(--border);
      border-radius: 16px;
      padding: 2.75rem 1.75rem 2rem;
      box-shadow: 0 4px 24px var(--shadow);
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 1.75rem;
      animation: slideUp .55s cubic-bezier(.22,1,.36,1) both;
      animation-delay: .1s;
    }

    .coin-stage {
      width: 260px;
      height: 260px;
      position: relative;
    }

    .coin {
      width: 100%;
      height: 100%;
      position: relative;
      cursor: default;
    }

    .face {
      position: absolute;
      inset: 0;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      transition: none;
    }

    .face-fail {
      background: #000;
      box-shadow: 0 6px 32px rgba(192,57,43,.45);
    }

    .face-pass {
      background: #000;
      box-shadow: 0 6px 28px rgba(39,174,96,.45);
    }

    .face-mystery {
      background: radial-gradient(circle at 38% 32%, #e2bc6a, var(--gold) 55%, var(--gold-dim));
      box-shadow:
        inset 0 0 0 6px rgba(255,255,255,.18),
        inset 0 -8px 24px rgba(0,0,0,.3),
        0 6px 28px rgba(201,168,76,.5);
    }

    .face::before {
      content: '';
      position: absolute;
      inset: 5px;
      border-radius: 50%;
      border: 2px solid rgba(255,255,255,.18);
      pointer-events: none;
      z-index: 1;
    }

    .face img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      border-radius: 50%;
      position: relative;
      z-index: 2;
    }

    .face-mystery svg {
      width: 100%;
      height: 100%;
      position: relative;
      z-index: 2;
    }

    @keyframes coinFlip {
      0%   { transform: scaleX(1); }
      50%  { transform: scaleX(0); }
      100% { transform: scaleX(1); }
    }

    .coin.spinning {
      animation: coinFlip var(--half-duration, 0.2s) ease-in-out var(--flip-count, 8) forwards;
    }

    @keyframes wobble {
      0%   { transform: scaleX(1) rotateZ(0deg); }
      20%  { transform: scaleX(1) rotateZ(2deg); }
      40%  { transform: scaleX(1) rotateZ(-1.5deg); }
      60%  { transform: scaleX(1) rotateZ(1deg); }
      80%  { transform: scaleX(1) rotateZ(-.5deg); }
      100% { transform: scaleX(1) rotateZ(0deg); }
    }

    .coin.wobbling {
      animation: wobble .5s ease-out forwards;
    }

    .result-banner {
      font-family: 'Cinzel', serif;
      font-size: 1.4rem;
      font-weight: 700;
      letter-spacing: .12em;
      text-transform: uppercase;
      opacity: 0;
      transform: translateY(8px);
      transition: opacity .35s ease, transform .35s ease;
      min-height: 2rem;
      text-align: center;
    }

    .result-banner.visible {
      opacity: 1;
      transform: translateY(0);
    }

    .result-banner.fail { color: var(--fail-red); }
    .result-banner.pass { color: var(--pass-grn); }

    .result-sub {
      font-size: .78rem;
      font-weight: 300;
      font-family: 'Lato', sans-serif;
      letter-spacing: .08em;
      color: var(--muted);
      margin-top: .2rem;
      min-height: 1.1rem;
      text-align: center;
      opacity: 0;
      transition: opacity .35s .15s ease;
    }

    .result-sub.visible { opacity: 1; }

    .btn-roll {
      font-family: 'Cinzel', serif;
      font-size: .85rem;
      font-weight: 600;
      letter-spacing: .14em;
      text-transform: uppercase;
      color: var(--ink);
      background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
      border: none;
      border-radius: 8px;
      padding: .9rem 2.4rem;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      box-shadow: 0 3px 12px rgba(201,168,76,.35), inset 0 1px 0 rgba(255,255,255,.4);
      transition: transform .12s ease, box-shadow .12s ease, opacity .2s;
      width: 100%;
      max-width: 280px;
      min-height: 48px;
      touch-action: manipulation;
    }

    .btn-roll::after {
      content: '';
      position: absolute;
      inset: 0;
      background: linear-gradient(135deg, rgba(255,255,255,.25) 0%, transparent 60%);
      pointer-events: none;
    }

    .btn-roll:hover:not(:disabled) {
      transform: translateY(-2px);
      box-shadow: 0 6px 20px rgba(201,168,76,.45), inset 0 1px 0 rgba(255,255,255,.4);
    }

    .btn-roll:active:not(:disabled) {
      transform: translateY(0);
      box-shadow: 0 2px 8px rgba(201,168,76,.3);
    }

    .btn-roll:disabled {
      opacity: .55;
      cursor: not-allowed;
    }

    /* .nav-link comes from styles.css */

    footer {
      padding-bottom: 1.5rem;
      text-align: center;
    }

    /* Local slideUp override — uses 28px (more dramatic entrance).
       styles.css defines slideUp at 14px; this overrides it for
       this page only. Remove to use the shared default. */
    @keyframes slideUp {
      from { opacity: 0; transform: translateY(28px); }
      to   { opacity: 1; transform: translateY(0); }
    }
  

/* ─────────────────────────────────────────
   LOOT PAGE
   The Loot Table: Draw random magical items
   with descriptions and optional images.
   Features: Shuffle-bag algorithm, image slots.
   ───────────────────────────────────────── */

  /* ⚠️  PAGE-SPECIFIC: All styles in this section are scoped to .loot-page */
  /* DO NOT use bare body/html/header/main selectors - use .loot-page <selector> */

  /* ── Page layout (body.loot-page defined in global page-body block above) ── */

  /* ── Header ── */
  /* .site-label, header h1, .subtitle come from styles.css */
  header {
    text-align: center;
    padding: 10px 16px 6px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
  }

  main {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 12px 16px 8px;
    min-height: 0;
  }

  .loot-card {
    width: 100%;
    max-width: 440px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 18px;
    padding: 28px 24px 24px;
    box-shadow: 0 6px 32px var(--shadow);
    display: flex;
    flex-direction: column;
    gap: 14px;
    animation: cardIn .5s cubic-bezier(.22,1,.36,1) both;
  }

  .item-image-slot {
    width: 100%;
    border-radius: 10px;
    background: linear-gradient(135deg, #f0ebe3 0%, #e8e2d9 100%);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    overflow: hidden;
    position: relative;
    min-height: 60px;
  }

  .item-image-slot.has-image {
    background: none;
    border-color: var(--border);
  }

  .item-image-slot.has-image img {
    width: 100%;
    height: auto;
    display: block;
  }

  .item-image-slot .slot-icon {
    font-size: 2rem;
    opacity: 0.5;
    line-height: 1;
  }

  .item-image-slot .slot-hash {
    font-family: 'Lato', monospace;
    font-size: 0.58rem;
    letter-spacing: .1em;
    color: var(--gold-dim);
    opacity: 0.7;
    text-transform: uppercase;
  }

  /* placeholder icon and hash text inside slot */

  .item-name-label {
    font-family: 'Cinzel', serif;
    font-size: .6rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin-bottom: 2px;
  }

  .item-name {
    font-family: 'Cinzel', serif;
    font-size: 1.35rem;
    font-weight: 700;
    color: var(--ink);
    line-height: 1.25;
    letter-spacing: .02em;
    transition: opacity .15s;
  }

  .item-flavour-label {
    font-family: 'Cinzel', serif;
    font-size: .6rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin-bottom: 2px;
  }

  .item-flavour {
    font-size: .95rem;
    font-weight: 300;
    line-height: 1.55;
    color: var(--ink);
    font-style: italic;
    transition: opacity .15s;
  }

  .item-name.fading,
  .item-flavour.fading { opacity: 0; }

  .card-divider {
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--border), transparent);
  }

  /* .source-badge base + .live/.fallback come from styles.css */
  /* align-self: center is local override for loot layout */
  .source-badge { align-self: center; }

  /* Diagnostic badge — expanded to show error detail */
  .source-badge.diag {
    flex-direction: column;
    align-items: flex-start;
    border-radius: 10px;
    padding: 6px 10px;
    gap: 3px;
    max-width: 100%;
    word-break: break-word;
    align-self: stretch;
  }

  .badge-row {
    display: flex;
    align-items: center;
    gap: 5px;
  }

  .badge-error {
    font-size: 0.60rem;
    color: #c0392b;
    letter-spacing: .02em;
    text-transform: none;
    font-style: italic;
    padding-left: 10px;
  }

  /* .card-footer comes from styles.css
     Padding is 9px 0 10px here (no side padding) — overrides shared value */
  .card-footer { padding: 16px 0 10px; }

  /* .pull-btn base + :active come from styles.css */
  /* Dark-theme hover: --ink-hover goes near-black, so we lighten it */
  [data-theme="dark"]  .pull-btn:hover  { background: #d8d0b8; }
  [data-theme="light"] .pull-btn:hover  { background: var(--ink-hover); }

  /* .loading + .loading .spinner come from styles.css */

  /* .nav-link comes from styles.css */
  footer {
    padding-bottom: 1.5rem;
    text-align: center;
  }

  /* @keyframes cardIn + @keyframes spin come from styles.css */


/* ─────────────────────────────────────────
   POLL PAGE & ADMIN PANEL
   The Poll: Live audience voting on questions.
   Admin panel for creating/managing polls.
   Features: Real-time results, vote tracking, admin controls.
   ───────────────────────────────────────── */

  /* ⚠️  PAGE-SPECIFIC: All styles in this section are scoped to .poll-page */
  /* DO NOT use bare body/html/header/main selectors - use .poll-page <selector> */

  /* ── Page layout (body.poll-page defined in global page-body block above) ── */

  /* ── Header ── */
  /* .site-label, header h1, .subtitle come from styles.css */
  header {
    text-align: center;
    padding: 12px 16px 8px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
  }

  /* ── Main ── */
  main {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 16px;
  }

  /* ── White card ── */
  .card {
    width: 100%;
    max-width: 480px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 18px;
    box-shadow: 0 6px 32px var(--shadow);
    overflow: hidden;
    animation: cardIn .45s cubic-bezier(.22,1,.36,1) both;
  }

  .card-body {
    padding: 22px 22px 0;
  }

  /* .card-footer base comes from styles.css
     Padding override: poll uses extra side padding */
  .card-footer { padding: 10px 22px 12px; }

  /* ── Admin badge ── */
  .admin-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-family: 'Cinzel', serif;
    font-size: .58rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--gold);
    border: 1px solid rgba(201,168,76,.35);
    background: rgba(201,168,76,.07);
    border-radius: 20px;
    padding: 3px 10px;
    margin-bottom: 14px;
    align-self: flex-start;
  }

  /* ── Question display ── */
  .question-label {
    font-family: 'Cinzel', serif;
    font-size: .58rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin-bottom: 5px;
  }

  .question-text {
    font-family: 'Cinzel', serif;
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.35;
    margin-bottom: 18px;
  }

  /* ── Vote buttons ── */
  .vote-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 18px;
  }

  .vote-btn {
    width: 100%;
    background: var(--parchment);
    border: 1.5px solid var(--border);
    border-radius: 10px;
    padding: 13px 16px;
    font-family: 'Cinzel', serif;
    font-size: .92rem;
    font-weight: 600;
    color: var(--ink);
    cursor: pointer;
    text-align: left;
    letter-spacing: .02em;
    transition: border-color .18s, background .18s, transform .1s, box-shadow .18s;
    display: flex;
    align-items: center;
    gap: 10px;
    position: relative;
    overflow: hidden;
  }

  .vote-btn .option-letter {
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--gold);
    flex-shrink: 0;
    min-width: 18px;
  }

  .vote-btn:hover:not(:disabled) {
    border-color: var(--gold);
    background: var(--gold-bg);
    box-shadow: 0 3px 12px rgba(201,168,76,.18);
    transform: translateY(-1px);
  }

  .vote-btn:active:not(:disabled) {
    transform: translateY(0);
  }

  .vote-btn:disabled {
    cursor: default;
  }

  /* ── Result bars ── */
  .result-bar-wrap {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 18px;
  }

  .result-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  .result-label-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
  }

  .result-option-name {
    font-family: 'Cinzel', serif;
    font-size: .82rem;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: .02em;
  }

  .result-pct {
    font-family: 'Cinzel', serif;
    font-size: .88rem;
    font-weight: 700;
    color: var(--gold);
  }

  .result-count {
    font-size: .68rem;
    color: var(--muted);
    margin-left: 5px;
  }

  .bar-track {
    height: 10px;
    background: var(--border);
    border-radius: 5px;
    overflow: hidden;
  }

  .bar-fill {
    height: 100%;
    border-radius: 5px;
    background: linear-gradient(90deg, var(--gold-dim), var(--gold));
    transition: width .6s cubic-bezier(.22,1,.36,1);
    width: 0%;
  }

  .bar-fill.winner {
    background: linear-gradient(90deg, #1e8449, var(--pass-grn));
  }

  /* Vote confirmation */
  .voted-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .7rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--pass-grn);
    font-weight: 700;
    margin-bottom: 8px;
  }

  .total-votes {
    font-size: .72rem;
    color: var(--muted);
    letter-spacing: .05em;
    text-align: center;
    margin-bottom: 10px;
  }

  /* ── Admin form ── */
  .form-group {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin-bottom: 12px;
  }

  .form-label {
    font-family: 'Cinzel', serif;
    font-size: .58rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: .14em;
    text-transform: uppercase;
  }

  .form-input {
    width: 100%;
    background: var(--parchment);
    border: 1.5px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    font-family: 'Lato', sans-serif;
    font-size: .92rem;
    font-weight: 400;
    color: var(--ink);
    outline: none;
    transition: border-color .18s;
  }

  .form-input:focus {
    border-color: var(--gold);
  }

  .form-input::placeholder {
    color: var(--muted);
    opacity: .7;
  }

  /* ── Buttons ── */
  /* .btn-primary base + hover/active/disabled come from styles.css */

  .btn-danger {
    width: 100%;
    background: none;
    color: var(--fail-red);
    border: 1px solid rgba(192,57,43,.35);
    border-radius: 8px;
    padding: 10px;
    font-family: 'Cinzel', serif;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .08em;
    cursor: pointer;
    transition: background .2s, border-color .2s;
  }

  .btn-danger:hover { background: rgba(192,57,43,.06); border-color: var(--fail-red); }

  .btn-ghost {
    width: 100%;
    background: none;
    color: var(--gold);
    border: 1px solid rgba(201,168,76,.4);
    border-radius: 8px;
    padding: 10px;
    font-family: 'Cinzel', serif;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .08em;
    cursor: pointer;
    transition: background .2s, border-color .2s;
  }

  .btn-ghost:hover { background: var(--gold-bg); border-color: var(--gold); }

  .divider {
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--border), transparent);
    margin: 4px 0;
  }

  /* ── Status states ── */
  .status-icon {
    font-size: 2rem;
    display: block;
    margin-bottom: 8px;
    text-align: center;
  }

  .status-heading {
    font-family: 'Cinzel', serif;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--ink);
    text-align: center;
    margin-bottom: 6px;
  }

  .status-body {
    font-size: .85rem;
    color: var(--muted);
    text-align: center;
    line-height: 1.55;
  }

  .status-body code {
    font-family: 'Lato', monospace;
    background: var(--parchment);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 1px 5px;
    font-size: .82rem;
    color: var(--ink);
    word-break: break-all;
  }

  /* .source-badge base + .live .dot come from styles.css */
  /* .demo is poll-specific (red dot = demo mode) */
  .source-badge.demo .dot   { background: var(--fail-red); }

  /* Admin result admin controls */
  .admin-results-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 14px;
  }

  .live-indicator {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: .65rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--pass-grn);
    font-weight: 700;
  }

  .live-dot {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--pass-grn);
    animation: livePulse 1.4s ease-in-out infinite;
  }

  @keyframes livePulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .3; }
  }

  /* ── Footer nav ── */
  /* .nav-link comes from styles.css */
  footer {
    text-align: center;
    padding: 6px 0 10px;
    flex-shrink: 0;
  }

  /* @keyframes cardIn + @keyframes spin come from styles.css */

  .spinner {
    display: inline-block;
    animation: spin 1.1s linear infinite;
    font-size: 1.4rem;
  }

  /* Waiting state pulse */
  .waiting-pulse {
    animation: waitPulse 2s ease-in-out infinite;
  }

  @keyframes waitPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .5; }
  }

  /* ── Dynamic option builder (admin form) ── */

  /* Row = letter tag + input + optional remove button */
  .option-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    animation: optionSlideIn .2s cubic-bezier(.22,1,.36,1) both;
  }

  @keyframes optionSlideIn {
    from { opacity: 0; transform: translateY(-5px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  .option-row .form-input {
    flex: 1;
    margin-bottom: 0;
  }

  /* Gold letter badge — A, B, C … */
  .option-letter-tag {
    font-family: 'Cinzel', serif;
    font-size: .65rem;
    font-weight: 700;
    letter-spacing: .1em;
    color: var(--gold);
    flex-shrink: 0;
    width: 16px;
    text-align: center;
  }

  /* ✕ remove button — only visible on options C/D/E */
  .btn-remove-option {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--muted);
    font-size: .85rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: border-color .15s, color .15s, background .15s;
  }

  .btn-remove-option:hover {
    border-color: var(--fail-red);
    color: var(--fail-red);
    background: rgba(192,57,43,.05);
  }

  /* Invisible spacer keeps required rows aligned with removable ones */
  .btn-remove-placeholder {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
  }

  /* Options section heading row */
  .options-section-label {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 8px;
  }

  .options-count-hint {
    font-family: 'Lato', sans-serif;
    font-size: .6rem;
    font-weight: 300;
    color: var(--muted);
    letter-spacing: .03em;
  }

  /* Dashed "add another option" button */
  .btn-add-option {
    width: 100%;
    background: none;
    border: 1.5px dashed var(--border);
    border-radius: 8px;
    padding: 9px 12px;
    font-family: 'Lato', sans-serif;
    font-size: .82rem;
    font-weight: 400;
    color: var(--muted);
    cursor: pointer;
    text-align: left;
    letter-spacing: .03em;
    transition: border-color .18s, color .18s, background .18s;
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
  }

  .btn-add-option:hover {
    border-color: var(--gold);
    color: var(--gold);
    background: var(--gold-bg);
  }

  .btn-add-option .add-plus {
    font-size: 1.1rem;
    line-height: 1;
    opacity: .55;
  }


/* ─────────────────────────────────────────
   QR CODE PAGE
   Displays a QR code with title and lightbox preview.
   Features: QR code generation, lightbox overlay.
   ───────────────────────────────────────── */

  /* ── Page layout (body.qrcode-page defined in global page-body block above) ── */

  /* ── Header ── */
  header {
    text-align: center;
    padding: 10px 16px 6px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
  }

  /* ── Main ── */
  main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px 16px;
    overflow: hidden;
  }

  /* ── QR card ── */
  .qr-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 18px;
    padding: 24px 24px 20px;
    box-shadow: 0 6px 32px var(--shadow);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    width: 100%;
    max-width: 320px;
  }

  .qr-title {
    font-family: 'Cinzel', serif;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--gold-dim);
    text-align: center;
  }

  .qr-img {
    width: 100%;
    max-height: 60vh;
    object-fit: contain;
    border-radius: 10px;
    cursor: pointer;
    display: block;
  }

  .qr-hint {
    font-size: .72rem;
    color: var(--muted);
    text-align: center;
    line-height: 1.5;
    margin: 0;
  }

  /* ── Footer ── */
  footer {
    text-align: center;
    padding: 10px 16px 14px;
    border-top: 1px solid var(--border);
    flex-shrink: 0;
  }


/* ─────────────────────────────────────────
   TRAITGEN PAGE
   Trait Generator: Roll a single trait with
   optional loot card display.
   Features: Mulligan system, trait display, loot preview.
   ───────────────────────────────────────── */

  /* ⚠️  PAGE-SPECIFIC: All styles in this section are scoped to .traitgen-page */
  /* DO NOT use bare body/html/header/main selectors - use .traitgen-page <selector> */

  /* ── Page layout (body.traitgen-page defined in global page-body block above) ── */

  /* ── Desktop wrapper — .page-frame base + media query come from styles.css ── */
  @media (min-width: 600px) {
    .page-frame { max-height: 820px; }
  }

  /* ── Header ── */
  /* .site-label, header h1, .subtitle come from styles.css */
  header {
    text-align: center;
    padding: 10px 16px 6px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    position: relative;
    background-color: var(--parchment);
  }

  /* .mulligan-bar, .pip-row, .pip, .pip.spent come from styles.css
     (they are identical to chargen.html — now centralised) */

  /* ── Main area ── */
  #app {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 0 12px 6px;
    min-height: 0;
    background-color: var(--parchment);
  }

  /* .loading + .loading .spinner come from styles.css */

  /* ── White card ── */
  .trait-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: 0 4px 24px var(--shadow);
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
    animation: cardIn .45s cubic-bezier(.22,1,.36,1) both;
  }

  /* ── Scrollable inner area (needed when loot expands the card) ── */
  .trait-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
  }

  .trait-scroll::-webkit-scrollbar { width: 4px; }
  .trait-scroll::-webkit-scrollbar-track { background: transparent; }
  .trait-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

  /* ── Standard trait display (non-loot) ── */
  .trait-display {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 32px 28px;
    gap: 16px;
    min-height: 100%;
    transition: opacity 0.2s ease;
  }

  .trait-display.fading { opacity: 0; }

  .trait-label {
    font-family: 'Cinzel', serif;
    font-size: 0.65rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: 0.18em;
    text-transform: uppercase;
  }

  /* The big trait text — large and prominent for phone screens */
  .trait-value {
    font-family: 'Cinzel', serif;
    font-size: clamp(1.45rem, 5vw, 2rem);
    font-weight: 700;
    color: var(--ink);
    line-height: 1.3;
    letter-spacing: 0.02em;
    text-align: center;
  }

  /* Gold divider under the trait text */
  .trait-divider {
    width: 60px;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--gold), transparent);
    flex-shrink: 0;
  }

  /* Sheet source label */
  .trait-source {
    font-family: 'Lato', sans-serif;
    font-size: 0.65rem;
    font-weight: 300;
    color: var(--muted);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-align: center;
    min-height: 1rem;
  }

  /* ── Loot display ──────────────────────────────────────────
     Rendered instead of .trait-display when the rolled entry
     comes from CONFIG.LOOT_TAB. Mirrors loot.html exactly.
  ────────────────────────────────────────────────────────── */
  .loot-display {
    display: flex;
    flex-direction: column;
    padding: 20px 20px 16px;
    gap: 12px;
    transition: opacity 0.2s ease;
  }

  .loot-display.fading { opacity: 0; }

  /* Image slot — mirrors loot.html .item-image-slot */
  .loot-image-slot {
    width: 100%;
    border-radius: 10px;
    background: linear-gradient(135deg, #f0ebe3 0%, #e8e2d9 100%);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    overflow: hidden;
    min-height: 60px;
  }

  .loot-image-slot.has-image {
    background: none;
    padding: 8px;
  }

  .loot-image-slot.has-image img {
    width: 100%;
    height: auto;
    display: block;
  }

  .loot-image-slot .slot-icon {
    font-size: 2rem;
    opacity: 0.5;
    line-height: 1;
  }

  /* Item name — large, matches .trait-value prominence */
  .loot-name-label {
    font-family: 'Cinzel', serif;
    font-size: .6rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin-bottom: 2px;
  }

  .loot-name {
    font-family: 'Cinzel', serif;
    font-size: clamp(1.2rem, 4.5vw, 1.6rem);
    font-weight: 700;
    color: var(--ink);
    line-height: 1.25;
    letter-spacing: .02em;
  }

  .loot-card-divider {
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--border), transparent);
  }

  /* Flavour text — mirrors loot.html .item-flavour */
  .loot-flavour-label {
    font-family: 'Cinzel', serif;
    font-size: .6rem;
    font-weight: 600;
    color: var(--gold);
    letter-spacing: .14em;
    text-transform: uppercase;
    margin-bottom: 2px;
  }

  .loot-flavour {
    font-size: .93rem;
    font-weight: 300;
    line-height: 1.55;
    color: var(--ink);
    font-style: italic;
  }

  /* Source tag at foot of loot block */
  .loot-source {
    font-family: 'Lato', sans-serif;
    font-size: 0.65rem;
    font-weight: 300;
    color: var(--muted);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-align: center;
  }

  /* .card-footer comes from styles.css */
  /* .roll-btn + all states come from styles.css */
  /* .lock-notice + .lock-msg + .lock-countdown come from styles.css */
  /* .source-badge + .dot + .live/.fallback come from styles.css */

  /* ── Footer nav ── */
  /* .nav-link comes from styles.css */
  footer {
    text-align: center;
    padding: 5px 0 7px;
    flex-shrink: 0;
    background-color: var(--parchment);
  }

  /* ================================================================
     DEV RESET BUTTON
     Remove or hide this before a live show — it is for testing only.
     To remove: delete the .reset-btn rule below AND the
     devReset() function AND the injection block inside render().
  ================================================================ */
  .reset-btn {
    position: absolute;
    top: 50%;
    right: 12px;
    transform: translateY(-50%);
    background: none;
    border: 1px solid #c0392b;
    border-radius: 5px;
    padding: 3px 8px;
    font-family: 'Lato', sans-serif;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #c0392b;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.2s;
  }
  .reset-btn:hover { opacity: 1; }
  /* ================================================================
     END DEV RESET BUTTON STYLES
  ================================================================ */

  /* @keyframes cardIn and @keyframes spin come from styles.css */
  .die.spinning { animation: spin 0.35s ease; }


/* ─────────────────────────────────────────
   PROFILE PAGE
   User authentication and profile display.
   Features: Sign-in form, profile data, section cards.
   ───────────────────────────────────────── */

  /* ⚠️  PAGE-SPECIFIC: All styles in this section are scoped to .profile-page */
  /* DO NOT use bare body/html/header/main selectors - use .profile-page <selector> */

  /* ── Profile page local styles ── */
  .profile-page { max-width: 540px; margin: 0 auto; padding: 24px 16px 80px; }

  /* sign-in panel */
  .signin-panel { display: flex; flex-direction: column; gap: 16px; }
  .signin-panel h1 { font-family: 'Cinzel', serif; font-size: 1.4rem; font-weight: 700;
    color: var(--gold); text-align: center; margin: 32px 0 8px; letter-spacing: .06em; }
  .signin-panel p.tagline { text-align: center; color: var(--text-muted); font-size: .85rem;
    margin: 0 0 8px; }

  .btn-google { display: flex; align-items: center; justify-content: center; gap: 10px;
    width: 100%; padding: 12px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--card-bg); color: var(--text); font-family: 'Lato', sans-serif;
    font-size: .95rem; font-weight: 700; cursor: pointer;
    transition: border-color .2s, box-shadow .2s; }
  .btn-google:hover { border-color: var(--gold); box-shadow: 0 2px 8px var(--shadow-gold); }

  .divider { display: flex; align-items: center; gap: 10px; color: var(--text-muted);
    font-size: .75rem; letter-spacing: .08em; text-transform: uppercase; }
  .divider::before, .divider::after { content: ''; flex: 1; height: 1px;
    background: var(--border); }

  .auth-form { display: flex; flex-direction: column; gap: 10px; }
  .auth-form input { width: 100%; padding: 10px 12px; border-radius: 6px;
    border: 1px solid var(--border); background: var(--card-bg); color: var(--text);
    font-family: 'Lato', sans-serif; font-size: .95rem; box-sizing: border-box;
    transition: border-color .2s; }
  .auth-form input:focus { outline: none; border-color: var(--gold); }
  .auth-form .btn-primary { width: 100%; padding: 11px; border-radius: 6px;
    border: none; background: var(--gold-dim); color: #1a1200;
    font-family: 'Cinzel', serif; font-size: .85rem; font-weight: 700;
    letter-spacing: .07em; text-transform: uppercase; cursor: pointer;
    transition: background .2s, box-shadow .2s; }
  .auth-form .btn-primary:hover { background: var(--gold);
    box-shadow: 0 2px 10px var(--shadow-gold); }

  .auth-toggle { text-align: center; font-size: .83rem; color: var(--text-muted); }
  .auth-toggle button { background: none; border: none; color: var(--gold); cursor: pointer;
    font-size: .83rem; font-family: 'Lato', sans-serif; text-decoration: underline;
    padding: 0; }

  .auth-error { background: rgba(200,60,60,.15); border: 1px solid rgba(200,60,60,.4);
    color: #f08080; border-radius: 6px; padding: 8px 12px;
    font-size: .83rem; display: none; }
  .auth-error.visible { display: block; }

  /* profile/sign-in visibility */
  .profile-panel { display: flex; flex-direction: column; gap: 20px; padding-top: 1.8rem; }
  .profile-panel.hidden, .signin-panel.hidden { display: none; }

  /* profile header */
  .profile-header { display: flex; align-items: center; gap: 14px;
    padding: 16px; background: var(--card-bg); border: 1px solid var(--border);
    border-radius: 10px; }
  .profile-avatar { width: 52px; height: 52px; border-radius: 50%;
    border: 2px solid var(--gold-dim); object-fit: cover; flex-shrink: 0; }
  .profile-avatar-placeholder { width: 52px; height: 52px; border-radius: 50%;
    border: 2px solid var(--gold-dim); background: var(--bg-alt);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.4rem; flex-shrink: 0; }
  .profile-header-info { flex: 1; min-width: 0; }
  .profile-header-info .name { font-family: 'Cinzel', serif; font-size: 1rem;
    font-weight: 700; color: var(--gold); overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
  .profile-header-info .email { font-size: .78rem; color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .btn-signout { padding: 7px 14px; border-radius: 6px; border: 1px solid var(--border);
    background: none; color: var(--text-muted); font-family: 'Lato', sans-serif;
    font-size: .78rem; cursor: pointer; white-space: nowrap;
    transition: border-color .2s, color .2s; }
  .btn-signout:hover { border-color: var(--gold-dim); color: var(--text); }
  .btn-reset-mulligans { padding: 7px 14px; border-radius: 6px; border: 1px solid #c0392b;
    background: none; color: #c0392b; font-family: 'Lato', sans-serif;
    font-size: .78rem; cursor: pointer; white-space: nowrap;
    opacity: 0.65; transition: border-color .2s, color .2s, opacity .2s; }
  .btn-reset-mulligans:hover { opacity: 1; }

  /* section cards */
  .profile-card { background: var(--card-bg); border: 1px solid var(--border);
    border-radius: 10px; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
  .profile-card h2 { font-family: 'Cinzel', serif; font-size: .9rem; font-weight: 700;
    color: var(--gold-dim); letter-spacing: .07em; text-transform: uppercase; margin: 0; }

  /* attendance + badges */
  .attendance-row { display: flex; align-items: center; gap: 10px; }
  .attendance-count { font-family: 'Cinzel', serif; font-size: 2rem; font-weight: 700;
    color: var(--gold); line-height: 1; }
  .attendance-label { font-size: .8rem; color: var(--text-muted); }
  .badges-grid { display: flex; flex-wrap: wrap; gap: 12px; }
  .badge-item { display: flex; flex-direction: column; align-items: center; gap: 4px; }
  .badge-item svg { width: 48px; height: 48px; }
  .badge-item .badge-name { font-size: .65rem; color: var(--text-muted);
    text-align: center; max-width: 56px; line-height: 1.2; }
  .no-badges { font-size: .83rem; color: var(--text-muted); }

  /* ticket verification */
  .ticket-status { display: flex; align-items: center; gap: 8px; font-size: .85rem; }
  .pill { padding: 2px 10px; border-radius: 20px; font-size: .72rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; }
  .pill--verified { background: rgba(60,180,80,.2); color: #6fda88;
    border: 1px solid rgba(60,180,80,.4); }
  .pill--pending { background: rgba(200,160,50,.15); color: var(--gold-dim);
    border: 1px solid rgba(200,160,50,.3); }
  .pill--none { background: rgba(120,120,120,.15); color: var(--text-muted);
    border: 1px solid var(--border); }
  .ticket-form { display: flex; gap: 8px; }
  .ticket-form input { flex: 1; padding: 9px 12px; border-radius: 6px;
    border: 1px solid var(--border); background: var(--card-bg); color: var(--text);
    font-family: 'Lato', sans-serif; font-size: .9rem; box-sizing: border-box; }
  .ticket-form input:focus { outline: none; border-color: var(--gold); }
  .ticket-form button { padding: 9px 16px; border-radius: 6px; border: none;
    background: var(--gold-dim); color: #1a1200; font-family: 'Cinzel', serif;
    font-size: .75rem; font-weight: 700; letter-spacing: .06em; cursor: pointer;
    text-transform: uppercase; white-space: nowrap; transition: background .2s; }
  .ticket-form button:hover { background: var(--gold); }
  .ticket-msg { font-size: .78rem; color: var(--text-muted); display: none; }
  .ticket-msg.visible { display: block; }

  /* character sheet */
  .char-field { display: flex; flex-direction: column; gap: 4px; }
  .char-field label { font-size: .75rem; font-family: 'Cinzel', serif;
    letter-spacing: .06em; color: var(--text-muted); text-transform: uppercase; }
  .char-field input, .char-field textarea {
    padding: 9px 12px; border-radius: 6px; border: 1px solid var(--border);
    background: var(--card-bg); color: var(--text); font-family: 'Lato', sans-serif;
    font-size: .9rem; box-sizing: border-box; resize: vertical; width: 100%; }
  .char-field input:focus, .char-field textarea:focus {
    outline: none; border-color: var(--gold); }
  .char-field input[readonly], .char-field textarea[readonly] {
    opacity: .65; cursor: default; }
  .char-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
  .btn-save { padding: 9px 20px; border-radius: 6px; border: none;
    background: var(--gold-dim); color: #1a1200; font-family: 'Cinzel', serif;
    font-size: .78rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
    cursor: pointer; transition: background .2s; }
  .btn-save:hover { background: var(--gold); }
  .btn-save:disabled { opacity: .4; cursor: default; }
  .char-locked-note { font-size: .75rem; color: var(--text-muted); }
  .char-save-msg { font-size: .78rem; color: var(--text-muted); display: none; }
  .char-save-msg.visible { display: block; }
  .char-save-msg.error { color: #f08080; }

  /* character sheet — randomize additions */
  .char-sheet-header {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: 8px;
  }
  .char-sheet-header h2 { margin: 0; }
  .mulligan-row {
    display: flex; align-items: center; gap: 8px;
    font-size: .72rem; color: var(--text-muted);
    font-family: 'Cinzel', serif; letter-spacing: .06em; text-transform: uppercase;
  }
  .char-pip-row { display: flex; gap: 5px; align-items: center; }
  .char-pip {
    width: 9px; height: 9px; background: var(--gold);
    transform: rotate(45deg); border-radius: 2px;
    transition: opacity .2s, background .2s;
  }
  .char-pip.spent { opacity: .18; }

  .btn-full-rand {
    width: 100%; padding: 9px; border-radius: 6px;
    border: 1px solid var(--gold-dim); background: transparent;
    color: var(--gold-dim); font-family: 'Cinzel', serif; font-size: .78rem;
    font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
    cursor: pointer; transition: background .2s, color .2s, border-color .2s;
  }
  .btn-full-rand:hover:not(:disabled) { background: var(--gold-dim); color: #1a1200; }
  .btn-full-rand:disabled { opacity: .32; cursor: default; }

  .char-input-row { display: flex; align-items: flex-start; gap: 6px; }
  .char-input-row input, .char-input-row textarea {
    flex: 1; min-width: 0;
  }
  .btn-rand, .btn-field-pin {
    flex-shrink: 0; padding: 7px 9px; border-radius: 6px;
    border: 1px solid var(--border); background: none; color: var(--text-muted);
    font-size: .82rem; line-height: 1; cursor: pointer; align-self: flex-start;
    transition: border-color .2s, color .2s, background .2s;
  }
  .btn-rand:hover:not(:disabled), .btn-field-pin:hover:not(:disabled) {
    border-color: var(--gold-dim); color: var(--gold-dim);
  }
  .btn-rand:disabled, .btn-field-pin:disabled { opacity: .28; cursor: default; }
  .btn-field-pin.pinned {
    border-color: var(--gold); color: var(--gold);
    background: rgba(201,168,76,.12);
  }

  /* ── Admin Showrunner Panel ── */
  /* Note: drawer open/close and layout now use shared .shelf / .shelf-* classes
     from styles.css. Only the admin-badge-pill remains here. */
  .admin-badge-pill {
    font-size: .56rem; padding: 1px 7px; border-radius: 12px; font-weight: 700;
    background: rgba(201,168,76,.15); border: 1px solid rgba(201,168,76,.4);
    letter-spacing: .1em; color: var(--gold-dim); vertical-align: middle;
  }

  /* poll form + results (shared with index.html) */
  .poll-admin-section { padding: 14px 14px 16px; display: flex; flex-direction: column; gap: 0; }
  .poll-admin-badge {
    display: inline-block; font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase; color: var(--gold);
    border: 1px solid rgba(201,168,76,.35); background: rgba(201,168,76,.10);
    border-radius: 20px; padding: 3px 10px; margin-bottom: 12px; align-self: flex-start;
  }
  .poll-form-group { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
  .poll-form-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase;
  }
  .poll-options-section-label {
    display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;
  }
  .poll-options-count-hint { font-size: .65rem; color: var(--text-muted); }
  .poll-form-input {
    width: 100%; box-sizing: border-box;
    background: rgba(255,255,255,.04); border: 1.5px solid var(--border);
    border-radius: 8px; padding: 10px 12px;
    font-family: 'Lato', sans-serif; font-size: .92rem; color: var(--text);
    outline: none; transition: border-color .18s;
  }
  .poll-form-input:focus { border-color: var(--gold); }
  .poll-form-input::placeholder { color: var(--text-muted); opacity: .7; }
  .poll-option-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
  .poll-option-letter-tag {
    font-family: 'Cinzel', serif; font-size: .65rem; font-weight: 700;
    letter-spacing: .1em; color: var(--gold); flex-shrink: 0; width: 16px; text-align: center;
  }
  .poll-btn-remove-option {
    flex-shrink: 0; width: 28px; height: 28px; background: none;
    border: 1px solid var(--border); border-radius: 6px; color: var(--text-muted);
    font-size: .85rem; cursor: pointer; display: flex; align-items: center; justify-content: center;
    transition: border-color .15s, color .15s, background .15s;
  }
  .poll-btn-remove-option:hover { border-color: #c0392b; color: #c0392b; background: rgba(192,57,43,.08); }
  .poll-btn-remove-placeholder { flex-shrink: 0; width: 28px; height: 28px; }
  .poll-btn-add-option {
    width: 100%; background: none; border: 1.5px dashed var(--border);
    border-radius: 8px; padding: 9px 12px;
    font-family: 'Lato', sans-serif; font-size: .82rem;
    color: var(--text-muted); cursor: pointer; text-align: left;
    transition: border-color .18s, color .18s, background .18s;
    display: flex; align-items: center; gap: 8px; margin-bottom: 12px;
  }
  .poll-btn-add-option:hover { border-color: var(--gold); color: var(--gold); }
  .poll-btn-launch {
    width: 100%; background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
    color: #1a1a2e; border: none; border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    box-shadow: 0 3px 10px rgba(201,168,76,.35); transition: opacity .18s;
  }
  .poll-btn-launch:hover { opacity: .9; }
  .poll-btn-launch:disabled { opacity: .4; cursor: not-allowed; }
  .poll-btn-reveal {
    width: 100%; background: linear-gradient(135deg, #27ae60 0%, #2ecc71 50%, #27ae60 100%);
    color: #fff; border: none; border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    box-shadow: 0 3px 10px rgba(39,174,96,.35); transition: opacity .18s;
  }
  .poll-btn-reveal:disabled { opacity: .4; cursor: not-allowed; }
  .poll-btn-new {
    width: 100%; background: rgba(201,168,76,.12); color: var(--gold);
    border: 1px solid rgba(201,168,76,.4); border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .75rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px; transition: background .2s;
  }
  .poll-btn-new:hover { background: rgba(201,168,76,.22); }
  .poll-btn-danger {
    width: 100%; background: none; color: #c0392b;
    border: 1px solid rgba(192,57,43,.35); border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .75rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    transition: background .2s, border-color .2s;
  }
  .poll-btn-danger:hover { background: rgba(192,57,43,.10); border-color: #c0392b; }
  .poll-admin-results-header {
    display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;
  }
  .poll-question-label {
    font-family: 'Cinzel', serif; font-size: .65rem; font-weight: 700;
    letter-spacing: .12em; text-transform: uppercase; color: var(--gold-dim); margin-bottom: 4px;
  }
  .poll-question-text { font-size: .92rem; color: var(--text); margin: 0 0 10px; }
  .poll-live-indicator {
    display: flex; align-items: center; gap: 5px; font-size: .65rem;
    letter-spacing: .08em; text-transform: uppercase; color: #27ae60; font-weight: 700;
  }
  .poll-live-dot {
    width: 6px; height: 6px; border-radius: 50%; background: #27ae60;
    animation: livePulse 1.4s ease-in-out infinite;
  }
   50%{opacity:.4;transform:scale(.75)} }
  .poll-result-wrap { display: flex; flex-direction: column; gap: 7px; margin-bottom: 8px; }
  .poll-result-row {}
  .poll-result-label-row {
    display: flex; justify-content: space-between; align-items: baseline;
    margin-bottom: 3px;
  }
  .poll-result-opt-name { font-size: .82rem; color: var(--text); }
  .poll-result-pct { font-size: .82rem; font-weight: 700; color: var(--gold); margin-right: 5px; }
  .poll-result-count { font-size: .72rem; color: var(--text-muted); }
  .bar-track { height: 6px; background: var(--border); border-radius: 3px; overflow: hidden; }
  .bar-fill { height: 100%; background: var(--gold-dim); border-radius: 3px; transition: width .4s; }
  .bar-fill.winner { background: var(--gold); }
  .total-votes { font-size: .75rem; color: var(--text-muted); margin: 4px 0 8px; }
  .poll-waiting {
    text-align: center; padding: 20px 12px;
    font-size: .82rem; color: var(--text-muted); line-height: 1.8;
  }

  /* back to vault cutout tab */
  .btn-back-vault {
    position: fixed; top: 0; right: 130px; z-index: 900;
    font-family: 'Cinzel', serif; font-size: .68rem; font-weight: 700;
    letter-spacing: .07em; text-transform: uppercase;
    color: var(--gold-dim); background: var(--card-bg);
    border: 1px solid var(--border); border-top: none;
    border-radius: 0 0 8px 8px; padding: 6px 14px; cursor: pointer;
    box-shadow: 0 3px 10px var(--shadow); opacity: .85;
    transition: opacity .2s, border-color .2s, color .2s, box-shadow .2s;
  }
  .btn-back-vault:hover {
    opacity: 1; border-color: var(--gold); color: var(--gold);
    box-shadow: 0 4px 14px var(--shadow-gold);
  }


/* ================================================
   NO DICE — SHARED STYLESHEET  (styles.css)
   Loaded by every page via <link rel="stylesheet">
   ================================================

   SECTION MAP
   1.  CSS Variables  (:root)
   2.  Box-sizing reset
   3.  Body base + parchment background
   4.  Header typography  (.site-label, h1 span)
   5.  Footer + nav link  (.nav-link)
   6.  Divider
   7.  Source badge + live/fallback dot
   8.  Loading spinner
   9.  Primary button  (.btn-primary / .roll-btn / .pull-btn)
   10. Card footer base  (.card-footer)
   11. Lock notice  (chargen + traitgen only)
   12. Mulligan bar + pips  (chargen + traitgen only)
   13. Shared animations  (cardIn, spin, slideUp)

   HOW TO USE THIS FILE
   - Change a colour in Section 1 to update it sitewide.
   - Page-specific styles live in each HTML file's own <style> block.
   - Do not hardcode hex values in component rules — always use
     a variable from Section 1.

   ================================================ */


/* ================================================
   1. CSS VARIABLES
   All colour tokens, shadows, and semantic aliases.
   Edit values here to retheme the whole site.
   ================================================ */

:root {
  /* Core palette */
  --ink:          #1a1a2e;   /* body text, dark backgrounds */
  --ink-hover:    #2e2e4a;   /* hover state for dark buttons */
  --parchment:    #faf7f2;   /* page background, light surfaces */

  /* Gold accent — headings, labels, interactive highlights */
  --gold:         #c9a84c;
  --gold-dim:     #a07c2e;   /* muted gold for eyebrow labels */
  --gold-bg:      #fffdf5;   /* very pale gold for hover fills */

  /* UI surfaces */
  --card-bg:      #ffffff;   /* white card backgrounds */
  --border:       #e8e2d9;   /* dividers, input borders */
  --muted:        #6b6676;   /* secondary / placeholder text */

  /* Elevation */
  --shadow:       rgba(26, 26, 46, .10);        /* standard card shadow */
  --shadow-gold:  rgba(201, 168, 76, .22);      /* gold-tinted shadow on hover */

  /* Semantic status colours */
  --success:      #2d7a5e;   /* live-data indicator dot (green) */
  --warning:      #b8860b;   /* fallback-data indicator dot (amber) */

  /* Pass / fail result colours (coinflip, poll) */
  --pass-grn:     #27ae60;
  --pass-rim:     #1e8449;
  --fail-red:     #c0392b;
  --fail-rim:     #922b21;

  /* No Dice accent — used by nodice theme */
  --nd-red:       rgba(235, 46, 46, 1);
  --nd-green:     rgba(0, 166, 81, 1);
}


/* ================================================
   2. BOX-SIZING RESET
   Makes all elements include padding inside their
   declared width/height — far more predictable.
   ================================================ */

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


/* ================================================
   3. BODY BASE + PARCHMENT BACKGROUND
   Shared font, colour, and background across every
   page. Layout properties (display/flex/height) are
   NOT set here because they vary per page — each
   HTML file adds those in its own <style> block.

   The background-image combines:
   - Two subtle gold radial glows (top-left, bottom-right)
   - An SVG fractal-noise texture overlay (paper grain)
   ================================================ */

.hidden { display: none !important; }

body {
  font-family: 'Lato', sans-serif;
  font-weight: 300;
  background-color: var(--parchment);
  color: var(--ink);
  background-image:
    radial-gradient(ellipse at 20% 10%, rgba(201,168,76,.08) 0%, transparent 60%),
    radial-gradient(ellipse at 80% 90%, rgba(201,168,76,.06) 0%, transparent 60%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
}


/* ================================================
   4. HEADER TYPOGRAPHY
   .site-label — small-caps eyebrow text above h1
                 e.g. "NO DICE — IMPROV RPG"
   h1 span     — the gold-coloured accent word
                 inside any heading

   NOTE: h1 itself is NOT here — font-size differs
   between the hub pages and the tool pages. Each
   file sets h1 in its own <style> block.
   ================================================ */

.site-label {
  font-family: 'Cinzel', serif;
  font-size: .6rem;
  font-weight: 400;
  letter-spacing: .25em;
  text-transform: uppercase;
  color: var(--gold-dim);
  margin-bottom: 2px;
}

/* Hub page: larger site-label */
@media (min-width: 600px) {
  .hub-header .site-label {
    font-size: 1rem;
    font-weight: 600;
    letter-spacing: .15em;
  }
}

h1 span {
  color: var(--gold);
  font-weight: 700;
}

/* Hub page: strong gold glow with horizontal lens flare effect */
.hub-header h1 span {
  text-shadow:
    0 0 20px rgba(201, 168, 76, 0.6),
    -8px 0 15px rgba(201, 168, 76, 0.4),
    8px 0 15px rgba(201, 168, 76, 0.4),
    0 2px 8px rgba(201, 168, 76, 0.5);
}


/* ================================================
   5. FOOTER + NAV LINK
   .nav-link — the "← Back to the Vault" link
   shown in the footer of every tool page.

   footer padding is NOT set here — it differs per
   page and lives in each file's own <style> block.
   ================================================ */

.nav-link {
  font-family: 'Cinzel', serif;
  font-size: .65rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold-dim);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color .2s, color .2s;
}

.nav-link:hover {
  color: var(--gold);
  border-color: var(--gold);
}


/* ================================================
   6. DIVIDER
   A thin gold gradient rule used under headings.

   The width is NOT set here — it varies per page
   (coinflip uses 80px, index uses 50px). Each page
   adds  .divider { width: Xpx; }  in its own block.
   ================================================ */

.divider,
.header-divider {
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
  margin: .9rem auto;
}

/* Hub header divider — narrower, tighter top margin */
.header-divider { width: 50px; margin-top: .75rem; }


/* ================================================
   7. SOURCE BADGE + LIVE DOT
   Shows whether data came from Google Sheets (live)
   or the built-in fallback arrays (fallback).

   Used by: chargen, loot, poll, traitgen

   Page-specific badge variants (.source-badge.diag
   in loot, .source-badge.demo in poll) stay in each
   file's own <style> block.
   ================================================ */

.source-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: .62rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2px 8px;
}

.source-badge .dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Green dot = data arrived from Google Sheets */
.source-badge.live .dot     { background: var(--success); }

/* Amber dot = API unreachable, showing built-in data */
.source-badge.fallback .dot { background: var(--warning); }


/* ================================================
   8. LOADING SPINNER
   Shown while Google Sheets data is being fetched.
   The .spinner element is an emoji inside .loading.

   Used by: chargen, loot, traitgen
   ================================================ */

.loading {
  text-align: center;
  padding: 40px 24px;
  color: var(--muted);
  font-size: .9rem;
  letter-spacing: .05em;
}

.loading .spinner {
  font-size: 2rem;
  margin-bottom: 12px;
  display: inline-block;
  animation: spin 1.2s linear infinite;
}


/* ================================================
   9. PRIMARY BUTTON BASE
   Dark ink background with parchment text.
   Three class names all share the same visual style:
     .roll-btn  — chargen, traitgen
     .pull-btn  — loot
     .btn-primary — poll (admin controls)

   To change the main button colour, edit here.

   NOTE: coinflip's gold-gradient button (.btn-roll)
   is a completely different visual — it stays in
   coinflip.html's own <style> block.
   ================================================ */

.btn-primary,
.roll-btn,
.pull-btn {
  width: 100%;
  background: var(--ink);
  color: var(--parchment);
  border: none;
  border-radius: 8px;
  padding: 11px;
  font-family: 'Cinzel', serif;
  font-size: .88rem;
  font-weight: 600;
  letter-spacing: .08em;
  cursor: pointer;
  transition: background .2s, transform .1s;
}

.btn-primary:hover:not(:disabled),
.roll-btn:hover:not(:disabled),
.pull-btn:hover { background: var(--ink-hover); }

.btn-primary:active,
.roll-btn:active,
.pull-btn:active { transform: scale(.98); }

.btn-primary:disabled,
.roll-btn:disabled { opacity: .35; cursor: not-allowed; }


/* ================================================
   10. CARD FOOTER BASE
   The bottom strip inside white cards. Contains
   the primary button and source badge.

   Used by: chargen, loot, poll, traitgen

   NOTE: poll.html uses extra side padding (22px)
   and overrides it in its own <style> block.
   ================================================ */

.card-footer {
  flex-shrink: 0;
  border-top: 1px solid var(--border);
  padding: 9px 14px 10px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  align-items: center;
  background: rgba(201,168,76,.02);
}


/* ================================================
   11. LOCK NOTICE  (chargen + traitgen only)
   Replaces the roll button when a player has used
   all their mulligans. Shows a countdown timer
   until the 1-hour lockout expires.
   ================================================ */

.lock-notice {
  width: 100%;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  cursor: default;
}

.lock-notice .lock-msg {
  font-family: 'Lato', sans-serif;
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: .02em;
  color: var(--muted);
}

.lock-notice .lock-countdown {
  font-family: 'Cinzel', serif;
  font-size: .88rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--ink);
  white-space: nowrap;
  flex-shrink: 0;
}


/* ================================================
   12. MULLIGAN BAR + PIPS  (chargen + traitgen only)
   Shows remaining re-roll tokens as small gold dots.
   Dots turn grey (.spent) as mulligans are used.

   traitgen.html originally labelled this block
   "copied exactly from chargen.html" — now it
   lives here instead.
   ================================================ */

.mulligan-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 5px 0 3px;
  font-size: .75rem;
  color: var(--muted);
  letter-spacing: .06em;
  text-transform: uppercase;
  flex-shrink: 0;
  background-color: var(--parchment);
}

.pip-row { display: flex; gap: 5px; }

.pip {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gold);
  transition: background .3s, transform .2s;
}

/* A spent pip turns grey and shrinks slightly */
.pip.spent { background: var(--border); transform: scale(.85); }


/* ================================================
   13. SHARED ANIMATIONS

   cardIn  — card slides up when first rendered.
             Used by most tool pages.

   spin    — full 360° rotation. Used by the
             loading spinner emoji and the die
             icon on reroll.

   slideUp — page-entry animation for cards on
             hub/index pages.

   IMPORTANT: coinflip.html overrides slideUp in
   its own <style> block with translateY(28px) for
   a more dramatic entrance. All other pages use
   the 14px value defined here.
   ================================================ */

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

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}


  to   { opacity: 1; transform: translateY(0); }
}

@keyframes nd-border-sweep {
  from { clip-path: polygon(0 0, 0 0, 0 100%, 0 100%); opacity: 1; }
  to   { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); opacity: 1; }
}

/* Houdini typed property — lets the browser interpolate --nd-angle as a true <angle>
   so conic-gradient(from var(--nd-angle), ...) can be CSS-animated. */
@property --nd-angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

@keyframes nd-border-rotate {
  to { --nd-angle: 360deg; }
}


/* ================================================
   14. DARK THEME  (index3.html)
   Activated by <html data-theme="dark">.
   Specificity: html[data-theme="dark"] = (0,1,1)
   definitively beats :root (0,1,0) — no cascade tie.
   Light mode simply falls back to the :root defaults
   above; no extra CSS block needed.
   ================================================ */

html[data-theme="dark"] {
  --ink:         #f0e8cc;   /* warm cream — body text on black */
  --ink-hover:   #1a1400;   /* very dark gold-black for button press */
  --parchment:   #0d0b00;   /* page background — near-black warm */
  --card-bg:     #141000;   /* dark warm black for cards */
  --border:      #3a2e00;   /* dark gold border */
  --muted:       #9a8a5a;   /* muted warm gold for secondary text */
  --gold-bg:     #1f1800;   /* dark gold fill for hover states */
  --shadow:      rgba(0, 0, 0, .55);
  --shadow-gold: rgba(201, 168, 76, .40);
  --success:     #27ae60;
  --warning:     #e2bc6a;
}

/* Dark body background — boosted gold radial glows readable on black */
html[data-theme="dark"] body {
  background-color: var(--parchment);
  background-image:
    radial-gradient(ellipse at 20% 10%, rgba(201,168,76,.12) 0%, transparent 60%),
    radial-gradient(ellipse at 80% 90%, rgba(201,168,76,.10) 0%, transparent 60%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
}

/* Buttons: --ink is now cream, so gold-bg buttons need explicit dark text */
html[data-theme="dark"] .btn-coin-flip           { color: #1a1a2e; }
html[data-theme="dark"] .cg-quick-cat-btn.active { color: #1a1a2e; }
html[data-theme="dark"] .full-link-btn           { color: #1a1a2e; }
html[data-theme="dark"] .full-link-btn:hover     { color: #1a1a2e; }

/* Full-link button: gold gradient on dark background */
html[data-theme="dark"] .full-link-btn {
  background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
  box-shadow: 0 3px 10px rgba(201,168,76,.35), inset 0 1px 0 rgba(255,255,255,.3);
}
html[data-theme="dark"] .full-link-btn:hover {
  background: linear-gradient(135deg, #e2bc6a 0%, var(--gold) 50%, #e2bc6a 100%);
}

/* Open shelf: green glow + border */
html[data-theme="dark"] .shelf.open {
  box-shadow: 0 6px 30px rgba(39,174,96,.22), 0 2px 12px rgba(201,168,76,.18);
  border-color: rgba(39,174,96,.38);
}
html[data-theme="dark"] .shelf.open .shelf-chevron { color: var(--pass-grn); }

/* Header divider: gold-to-green gradient */
html[data-theme="dark"] .header-divider {
  background: linear-gradient(90deg, var(--gold-dim), var(--pass-grn), var(--gold-dim));
  opacity: .75;
}

/* Vote buttons: green hover glow */
html[data-theme="dark"] .vote-btn:hover:not(:disabled) {
  border-color: var(--pass-grn);
  background: rgba(39,174,96,.10);
  box-shadow: 0 2px 10px rgba(39,174,96,.20);
}

/* Section divider: faint green-to-red sweep */
html[data-theme="dark"] .section-rule {
  background: linear-gradient(90deg, transparent, rgba(192,57,43,.35) 20%, rgba(39,174,96,.35) 80%, transparent);
}

/* Lock bar */
html[data-theme="dark"] .lock-bar {
  background: rgba(201,168,76,.10);
  border: 1px solid var(--border);
}


/* ================================================
   14b. NODICE THEME  (data-theme="nodice")
   Pop-art: black backgrounds, red primary accent,
   white card surfaces, coin-gold highlights.
   ================================================ */

html[data-theme="nodice"] {
  --ink:         rgba(255, 255, 255, 1);
  --ink-hover:   rgba(0, 0, 0, 1);
  --parchment:   rgba(0, 0, 0, 1);
  --card-bg:     rgba(0, 0, 0, 1);
  --border:      rgba(235, 46, 46, 1);
  --muted:       rgba(180, 180, 180, 1);
  --gold:        rgba(156, 123, 46, 1);
  --gold-dim:    rgba(120, 95, 35, 1);
  --gold-bg:     rgba(156, 123, 46, .12);
  --shadow:      rgba(0, 0, 0, .70);
  --shadow-gold: rgba(235, 46, 46, .35);
  --success:     rgba(0, 166, 81, 1);
  --warning:     rgba(235, 46, 46, .80);
  --pass-grn:    rgba(0, 166, 81, 1);
  --pass-rim:    rgba(0, 130, 63, 1);
  --fail-red:    rgba(235, 46, 46, 1);
  --fail-rim:    rgba(190, 30, 30, 1);
}

/* Page background: black with red/green coin-color radial accents */
html[data-theme="nodice"] body {
  background-color: var(--parchment);
  background-image:
    radial-gradient(ellipse at 20% 10%, rgba(235,46,46,.10) 0%, transparent 55%),
    radial-gradient(ellipse at 80% 90%, rgba(0,166,81,.07) 0%, transparent 55%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
}

/* Pop-art primary buttons: gold bg, black text */
html[data-theme="nodice"] .btn-primary,
html[data-theme="nodice"] .roll-btn,
html[data-theme="nodice"] .pull-btn {
  background: var(--gold);
  color: rgba(0, 0, 0, 1);
}
html[data-theme="nodice"] .btn-primary:hover:not(:disabled),
html[data-theme="nodice"] .roll-btn:hover:not(:disabled),
html[data-theme="nodice"] .pull-btn:hover {
  background: rgba(180, 142, 52, 1);
  color: rgba(0, 0, 0, 1);
}

/* Gold-bg buttons that need explicit dark text (same as dark theme) */
html[data-theme="nodice"] .btn-coin-flip           { color: rgba(0, 0, 0, 1); }
html[data-theme="nodice"] .cg-quick-cat-btn.active { color: rgba(0, 0, 0, 1); }
html[data-theme="nodice"] .full-link-btn           { color: rgba(0, 0, 0, 1); }
html[data-theme="nodice"] .full-link-btn:hover     { color: rgba(0, 0, 0, 1); }

/* Full-link button: gold gradient on black */
html[data-theme="nodice"] .full-link-btn {
  background: linear-gradient(135deg, var(--gold) 0%, rgba(196,160,74,1) 50%, var(--gold) 100%);
  box-shadow: 0 3px 10px rgba(156,123,46,.35), inset 0 1px 0 rgba(255,255,255,.25);
}
html[data-theme="nodice"] .full-link-btn:hover {
  background: linear-gradient(135deg, rgba(196,160,74,1) 0%, var(--gold) 50%, rgba(196,160,74,1) 100%);
}

/* Shelf at rest: red border (via --border token override above) */
/* Shelf open: green glow + sweep animation trigger */
html[data-theme="nodice"] .shelf.open {
  box-shadow: 0 6px 30px rgba(0,166,81,.25), 0 2px 12px rgba(235,46,46,.20);
  border-color: rgba(0, 166, 81, 1);
}
html[data-theme="nodice"] .shelf.open .shelf-chevron { color: var(--pass-grn); }

/* Nodice rotating sparkle border:
   Override the base clip-path and swap in a rotating conic-gradient.
   White hot-spot sweeps red→white→green continuously while the shelf is open. */
html[data-theme="nodice"] .shelf::before {
  clip-path: none;
  background:
    conic-gradient(from var(--nd-angle),
      rgba(235, 46, 46, 0.7)    0deg,
      rgba(235, 46, 46, 1)     70deg,
      rgba(255, 255, 255, 0.95) 90deg,
      rgba(0, 166, 81, 1)     110deg,
      rgba(0, 166, 81, 0.7)   190deg,
      rgba(235, 46, 46, 0.7)  360deg)
    border-box;
}

html[data-theme="nodice"] .shelf.open::before {
  opacity: 1;
  animation: nd-border-rotate 3s linear infinite;
}

/* Header divider: red-to-green gradient */
html[data-theme="nodice"] .header-divider {
  background: linear-gradient(90deg, var(--gold-dim), rgba(235,46,46,.8), rgba(0,166,81,.8), var(--gold-dim));
  opacity: .85;
}

/* Vote buttons: red hover glow */
html[data-theme="nodice"] .vote-btn:hover:not(:disabled) {
  border-color: rgba(235, 46, 46, 1);
  background: rgba(235, 46, 46, .10);
  box-shadow: 0 2px 10px rgba(235, 46, 46, .20);
}

/* Section divider: red-to-green sweep */
html[data-theme="nodice"] .section-rule {
  background: linear-gradient(90deg, transparent, rgba(235,46,46,.4) 20%, rgba(0,166,81,.4) 80%, transparent);
}

/* Lock bar: red-tinted */
html[data-theme="nodice"] .lock-bar {
  background: rgba(235, 46, 46, .08);
  border: 1px solid rgba(235, 46, 46, .30);
}

/* Profile button gold border in nodice */
html[data-theme="nodice"] .profile-btn { background: var(--card-bg); }
html[data-theme="nodice"] .profile-btn:hover,
html[data-theme="nodice"] .profile-btn--signed-in {
  border-color: var(--gold);
  color: var(--gold);
}

/* Shelf header hover overlay: red tint instead of gold */
html[data-theme="nodice"] .shelf-header::after {
  background: linear-gradient(110deg, rgba(235,46,46,.06) 0%, transparent 60%);
}

/* No Dice theme: header text colors */
html[data-theme="nodice"] .site-label {
  color: rgba(156, 123, 46, 1);
}

html[data-theme="nodice"] header h1 {
  color: rgba(255, 255, 255, 1);
}

html[data-theme="nodice"] h1 span {
  color: rgba(156, 123, 46, 1);
}

html[data-theme="nodice"] .tagline {
  color: rgba(255, 255, 255, 0.7);
}

/* Profile button: red border in No Dice theme (matches shelves) */
html[data-theme="nodice"] .profile-btn {
  background: var(--card-bg);
  border-color: rgba(235, 46, 46, 1);
  color: var(--text);
}

html[data-theme="nodice"] .profile-btn:hover,
html[data-theme="nodice"] .profile-btn--signed-in {
  border-color: rgba(0, 166, 81, 1);
  color: rgba(0, 166, 81, 1);
  box-shadow: 0 4px 14px rgba(0, 166, 81, 0.3);
}

/* Shelf content area: faint red tint */
html[data-theme="nodice"] .shelf-content {
  background: rgba(235, 46, 46, .03);
}

/* Source badge: gold border instead of red */
html[data-theme="nodice"] .source-badge {
  border-color: rgba(156, 123, 46, .35);
}

/* ================================================
   15. TOOL-PAGE HEADER TYPOGRAPHY
   Shared by chargen, coinflip (via h1 override),
   loot, traitgen, poll, qrcode.
   Hub pages (index.html) override h1 in their own
   inline <style> block with a larger clamp() size.
   ================================================ */

header h1 {
  font-family: 'Cinzel', serif;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: .04em;
  line-height: 1.2;
}

/* Eyebrow subtitle below h1 on tool pages */
.subtitle {
  font-size: .68rem;
  color: var(--muted);
  letter-spacing: .08em;
  text-transform: uppercase;
  margin-top: 2px;
}


/* ================================================
   16. PAGE-FRAME  (chargen + traitgen)
   Mobile-fill / desktop-window container.
   Each page keeps its unique max-height override
   in its own inline <style> block.
   ================================================ */

.page-frame {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
}

@media (min-width: 600px) {
  body:has(.page-frame) {
    align-items: center;
    justify-content: center;
  }
  .page-frame {
    width: 420px;
    height: 92dvh;
    border-radius: 20px;
    overflow: hidden;
    box-shadow: 0 8px 48px rgba(26,26,46,.18), 0 2px 8px rgba(26,26,46,.08);
    border: 1px solid var(--border);
  }
}


/* ── Theme toggle button (used by index3.html) ── */
.theme-toggle-btn {
  position: fixed; top: 0; left: 16px; z-index: 100;
  background: var(--card-bg);
  border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 8px 8px;
  padding: 6px 12px; font-size: 1rem; line-height: 1; cursor: pointer;
  box-shadow: 0 3px 10px var(--shadow);
  opacity: 0.85; transition: opacity .2s, border-color .2s, box-shadow .2s;
  touch-action: manipulation;
}
.theme-toggle-btn:hover {
  opacity: 1;
  border-color: var(--gold);
  box-shadow: 0 4px 14px var(--shadow-gold);
}

/* ================================================
   PROFILE / LOGIN BUTTON
   Upper-right fixed tab — mirrors theme toggle.
   Larger: includes text label.
   ================================================ */
.profile-btn {
  position: fixed;
  top: 0;
  right: 16px;
  z-index: 900;
  font-family: 'Cinzel', serif;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--gold-dim);
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 8px 8px;
  padding: 6px 14px;
  cursor: pointer;
  box-shadow: 0 3px 10px var(--shadow);
  opacity: 0.85;
  transition: opacity .2s, border-color .2s, color .2s, box-shadow .2s, background .2s;
  touch-action: manipulation;
  white-space: nowrap;
}

.profile-btn:hover {
  opacity: 1;
  border-color: var(--gold);
  color: var(--gold);
  box-shadow: 0 4px 14px var(--shadow-gold);
}

.profile-btn--signed-in {
  opacity: 1;
  border-color: var(--gold);
  color: var(--gold);
}

html[data-theme="dark"] .profile-btn { background: var(--card-bg); }
html[data-theme="dark"] .profile-btn:hover,
html[data-theme="dark"] .profile-btn--signed-in {
  border-color: var(--gold);
  color: var(--gold);
}


/* ================================================
   17. INDEX PAGE  (index.html)
   Hub layout, shelf accordion, coin flip, character
   generator, loot, poll, trait generator, and
   coming-soon grid.
   ================================================ */

  /* ── Poll admin inline styles (replaces poll.html?admin iframe) ── */
  .poll-admin-badge {
    display: inline-flex; align-items: center; gap: 5px;
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    letter-spacing: .14em; text-transform: uppercase;
    color: var(--gold); border: 1px solid rgba(201,168,76,.35);
    background: rgba(201,168,76,.10); border-radius: 20px;
    padding: 3px 10px; margin-bottom: 12px; align-self: flex-start; display: block;
  }
  .poll-form-group { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
  .poll-form-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase;
  }
  .poll-form-input {
    width: 100%; background: rgba(255,255,255,.04); border: 1.5px solid var(--border);
    border-radius: 8px; padding: 10px 12px;
    font-family: 'Lato', sans-serif; font-size: .92rem; color: var(--ink);
    outline: none; transition: border-color .18s;
  }
  .poll-form-input:focus { border-color: var(--gold); }
  .poll-form-input::placeholder { color: var(--muted); opacity: .7; }
  .poll-btn-launch {
    width: 100%;
    background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
    color: #1a1a2e; border: none; border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    box-shadow: 0 3px 10px rgba(201,168,76,.35);
    transition: opacity .18s, transform .1s;
  }
  .poll-btn-launch:hover { opacity: .9; } .poll-btn-launch:disabled { opacity: .4; cursor: not-allowed; }
  .poll-btn-reveal {
    width: 100%;
    background: linear-gradient(135deg, var(--pass-grn) 0%, #2ecc71 50%, var(--pass-grn) 100%);
    color: #fff; border: none; border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    box-shadow: 0 3px 10px rgba(39,174,96,.35);
    transition: opacity .18s, transform .1s;
  }
  .poll-btn-reveal:disabled { opacity: .4; cursor: not-allowed; }
  .poll-btn-new {
    width: 100%; background: rgba(201,168,76,.12); color: var(--gold);
    border: 1px solid rgba(201,168,76,.4); border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .75rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    transition: background .2s;
  }
  .poll-btn-new:hover { background: rgba(201,168,76,.2); }
  .poll-btn-danger {
    width: 100%; background: none; color: var(--fail-red);
    border: 1px solid rgba(192,57,43,.35); border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .75rem; font-weight: 600;
    letter-spacing: .08em; cursor: pointer; margin-bottom: 6px;
    transition: background .2s, border-color .2s;
  }
  .poll-btn-danger:hover { background: rgba(192,57,43,.10); border-color: var(--fail-red); }
  .poll-admin-results-header {
    display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;
  }
  .poll-live-indicator {
    display: flex; align-items: center; gap: 5px; font-size: .65rem;
    letter-spacing: .08em; text-transform: uppercase; color: var(--pass-grn); font-weight: 700;
  }
  .poll-live-dot {
    width: 6px; height: 6px; border-radius: 50%; background: var(--pass-grn);
    animation: livePulse 1.4s ease-in-out infinite;
  }
  .poll-option-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
  .poll-option-letter-tag {
    font-family: 'Cinzel', serif; font-size: .65rem; font-weight: 700;
    letter-spacing: .1em; color: var(--gold); flex-shrink: 0; width: 16px; text-align: center;
  }
  .poll-btn-remove-option {
    flex-shrink: 0; width: 28px; height: 28px; background: none;
    border: 1px solid var(--border); border-radius: 6px; color: var(--muted);
    font-size: .85rem; cursor: pointer; display: flex; align-items: center; justify-content: center;
    transition: border-color .15s, color .15s, background .15s;
  }
  .poll-btn-remove-option:hover { border-color: var(--fail-red); color: var(--fail-red); background: rgba(192,57,43,.08); }
  .poll-btn-remove-placeholder { flex-shrink: 0; width: 28px; height: 28px; }
  .poll-options-section-label {
    display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;
  }
  .poll-options-count-hint {
    font-family: 'Lato', sans-serif; font-size: .6rem; font-weight: 300;
    color: var(--muted); letter-spacing: .03em;
  }
  .poll-btn-add-option {
    width: 100%; background: none; border: 1.5px dashed var(--border);
    border-radius: 8px; padding: 9px 12px;
    font-family: 'Lato', sans-serif; font-size: .82rem; font-weight: 400;
    color: var(--muted); cursor: pointer; text-align: left; letter-spacing: .03em;
    transition: border-color .18s, color .18s, background .18s;
    display: flex; align-items: center; gap: 8px; margin-bottom: 12px;
  }
  .poll-btn-add-option:hover { border-color: var(--gold); color: var(--gold); background: var(--gold-bg); }
  .poll-admin-section { padding: 12px 12px 14px; }

  /* ── Page layout ──
     Mirrors profile.html's approach: block centering via max-width + margin auto.
     body.index-page is body WITH the class (not .index-page body = body inside .index-page).
     No flex on body — .page-wrap centers itself as a block element.

     WIDTH-LOCK STRATEGY (prevents shelves from resizing when content is generated):
     Shelf widths must be static on mobile. Any element that overflows its container
     can push the body into a horizontal scroll state, which changes what "100%"
     resolves to for every child — causing all shelves to shift width simultaneously.
     The fix is a three-layer clamp: body → .page-wrap → main each opt out of
     horizontal overflow so nothing inside can escape and reflow the layout.
  */
  body.index-page {
    min-height: 100dvh;
    overflow-x: hidden; /* Layer 1: prevents body scroll zone from forming */
    width: 100%;        /* explicit width so children resolve % against the viewport */
  }

  .page-wrap {
    max-width: 480px;
    width: 100%;        /* explicit width; max-width alone does not prevent content escape */
    margin: 0 auto;
    padding: 0 14px 32px;
    overflow-x: clip;   /* Layer 2: clips overflow without creating a scroll container.
                           Use 'clip' not 'hidden' — 'hidden' breaks position:fixed children
                           (e.g. theme-toggle-btn, profile-btn). 'clip' does not. */
  }

  /* ── Header ──
     border-bottom: none overrides the inherited solid border from bare header {}
     rules in other page sections (e.g. chargen, qrcode). Those rules apply
     globally and add a 1px solid border that bleeds across the full content
     area. The hub uses a .section-rule div below the header instead, which
     provides the same visual separator with a gradient fade. */
  header {
    text-align: center;
    padding: 1.6rem 0 .3rem;
    position: relative;
    background: transparent;
    border-bottom: none;
  }
  /* .site-label comes from styles.css */
  .hub-header h1 {
    font-family: 'Cinzel', serif;
    font-size: clamp(2rem, 7vw, 2.8rem);
    font-weight: 700;
    color: var(--ink);
    line-height: 1.1;
    letter-spacing: .08em;
    text-shadow: 0 2px 8px rgba(201, 168, 76, 0.25);
  }
  /* h1 span gold colour comes from styles.css */
  .tagline {
    margin-top: .35rem;
    font-size: .75rem;
    font-weight: 300;
    color: var(--muted);
    letter-spacing: .05em;
  }
  /* .header-divider width, gradient, and height come from styles.css */

  /* ── Main ──
     Resets align/justify from other page sections that bleed in via bare main{} selectors.
     width: 100% + min-width: 0 = Layer 3 of the width-lock strategy.
     Flex children default to min-width: auto, which lets content push the column wider.
     min-width: 0 disables that, so no shelf can ever widen the column it lives in. */
  .page-wrap > main {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 10px;
    padding: .9rem 0 1rem;
    width: 100%;    /* Layer 3a: locks column to container */
    min-width: 0;   /* Layer 3b: disables flex-child auto minimum */
  }

  /* ── SHELF ──
     width: 100% + min-width: 0 mirrors the pattern on .page-wrap > main.
     Each shelf is a flex child of main; without these, a shelf can grow wider
     than its siblings when JS injects content into it, shifting all shelf edges. */
  .shelf {
    position: relative;
    width: 100%;    /* lock to column width */
    min-width: 0;   /* prevent flex-child auto minimum from overriding the lock */
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: 0 2px 14px var(--shadow);
    overflow: hidden;
    transition: box-shadow .25s ease, border-color .25s ease;
    animation: slideUp .4s cubic-bezier(.22,1,.36,1) both;
  }

  /* Nodice animated border ring — conic-gradient sweep, clipped by clip-path wipe */
  .shelf::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 15px;
    border: 2px solid transparent;
    background:
      conic-gradient(from 45deg,
        rgba(235, 46, 46, 1)   0deg,
        rgba(0, 166, 81, 1)  180deg,
        rgba(235, 46, 46, 1) 360deg)
      border-box;
    -webkit-mask:
      linear-gradient(#fff 0 0) padding-box,
      linear-gradient(#fff 0 0);
    -webkit-mask-composite: destination-out;
    mask-composite: exclude;
    opacity: 0;
    pointer-events: none;
    z-index: 1;
    clip-path: polygon(0 0, 0 0, 0 100%, 0 100%);
  }

  .shelf.open {
    box-shadow: 0 6px 28px var(--shadow-gold);
    border-color: rgba(201,168,76,.35);
  }
  .shelf:nth-child(1) { animation-delay: .06s; }
  .shelf:nth-child(2) { animation-delay: .10s; }
  .shelf:nth-child(3) { animation-delay: .14s; }
  .shelf:nth-child(4) { animation-delay: .18s; }
  .shelf:nth-child(5) { animation-delay: .22s; }

  /* Shelf header (clickable row) */
  .shelf-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 14px 11px 12px;
    cursor: pointer;
    user-select: none;
    position: relative;
    -webkit-tap-highlight-color: transparent;
    touch-action: none; /* prevent browser scroll-detection from firing pointercancel during long-press */
  }
  .shelf-header::after {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(110deg, rgba(201,168,76,.06) 0%, transparent 60%);
    opacity: 0; transition: opacity .18s; pointer-events: none;
  }
  .shelf.open .shelf-header::after,
  .shelf-header:hover::after { opacity: 1; }

  .shelf-icon {
    font-size: 1.5rem; line-height: 1; flex-shrink: 0;
    width: 36px; text-align: center;
    filter: drop-shadow(0 1px 3px rgba(26,26,46,.12));
  }
  .shelf-text { flex: 1; min-width: 0; }
  .shelf-name {
    font-family: 'Cinzel', serif; font-size: .8rem; font-weight: 600;
    letter-spacing: .08em; text-transform: uppercase; color: var(--ink); line-height: 1.2;
  }
  .shelf-desc { font-size: .7rem; font-weight: 300; color: var(--muted); line-height: 1.35; margin-top: 1px; }
  .shelf-chevron {
    flex-shrink: 0; width: 20px; height: 20px;
    display: flex; align-items: center; justify-content: center;
    color: var(--gold-dim); transition: transform .3s cubic-bezier(.22,1,.36,1), color .2s;
    font-size: .75rem;
  }
  .shelf.open .shelf-chevron { transform: rotate(180deg); color: var(--gold); }

  /* Shelf slide-down body — CSS grid accordion (grid-template-rows 0fr → 1fr).
     grid-template-columns: 1fr is critical: without it, grid defaults to
     "auto" columns which size to content rather than to the container.
     width: 100% on .shelf-body and its children carries the width-lock
     through the full DOM depth to wherever JS renders content. */
  .shelf-body {
    display: grid;
    grid-template-rows: 0fr;
    grid-template-columns: 1fr; /* fills container; DO NOT remove — reverts to content-sized auto */
    width: 100%;
    transition: grid-template-rows .35s cubic-bezier(.22,1,.36,1);
  }
  .shelf.open .shelf-body { grid-template-rows: 1fr; }
  .shelf-body-inner { overflow: hidden; width: 100%; min-width: 0; }
  .shelf-content {
    border-top: 1px solid var(--border);
    background: rgba(201,168,76,.05);
    width: 100%;    /* direct parent of all JS-injected shelf content */
    min-width: 0;
  }

  /* ── SHELF DRAG-REORDER ── */
  /* Gold ring ripple fires once when .dragging is added by startDrag() */
  @keyframes shelf-drag-activate {
    0%   { box-shadow: 0 2px 14px var(--shadow), 0 0 0 0 rgba(201,168,76,.6); }
    60%  { box-shadow: 0 12px 36px var(--shadow-gold), 0 0 0 16px rgba(201,168,76,0); }
    100% { box-shadow: 0 12px 36px var(--shadow-gold); }
  }
  .shelf.dragging {
    animation: shelf-drag-activate 0.35s ease-out forwards;
    transform: scale(1.02);
    border-color: var(--gold);
    opacity: 0.88;
    z-index: 100;
    position: relative;
    cursor: grabbing;
  }
  .shelf.drag-placeholder {
    border: 2px dashed var(--gold);
    background: rgba(201,168,76,.07);
    border-radius: 16px;
    opacity: 0.6;
  }
  .shelf-header.reorder-active {
    cursor: grabbing;
  }

  /* ── PROFILE PAGE — shelf adjustments ── */
  /* Shelves render after Firebase auth; skip the slideUp entrance animation */
  .profile-panel .shelf { animation: none; }
  /* Content padding inside profile shelves (replaces .profile-card padding) */
  .profile-shelf-content { padding: 14px 16px 16px; }
  /* Ticket section hint text — replaces inline style="font-size:.8rem;…" */
  .ticket-hint { font-size: .8rem; color: var(--text-muted); margin: 0; }
  /* Backstory button column — replaces inline display:flex on wrapper div */
  .char-btn-stack { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
  /* Poll inner/footer sizing — moved from inline style attrs in profile.html */
  #poll-inner  { min-height: 48px; }
  #poll-footer { padding: 0 14px 10px; }

  /* ── SHELF-SPECIFIC SHARED HELPERS ── */
  .inner-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .16em; text-transform: uppercase; margin-bottom: 8px;
  }
  .full-link-btn {
    display: flex; align-items: center; justify-content: space-between;
    width: 100%; background: var(--ink); color: var(--parchment);
    border: none; border-radius: 8px; padding: 9px 14px;
    font-family: 'Cinzel', serif; font-size: .78rem; font-weight: 600;
    letter-spacing: .08em; text-transform: uppercase; text-decoration: none;
    cursor: pointer; transition: background .2s;
  }
  .full-link-btn:hover { background: var(--ink-hover); }
  .full-link-btn span { opacity: .6; font-size: .8rem; }

  /* .source-badge base styles come from styles.css */

  /* Shelf top-bar: full-link + optional badge side by side */
  .shelf-topbar {
    padding: 10px 12px 0;
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .shelf-topbar .full-link-btn { flex: 1; }

  /* ─────────────────────────────────────────
     COIN FLIP — wide layout
     Left: button + result text
     Right: coin (square)
  ───────────────────────────────────────── */

  .coin-wide {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0;
    padding: 14px 12px 14px;
  }

  /* Left column */
  .coin-left {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 10px;
    padding-right: 12px;
  }

  .btn-coin-flip {
    font-family: 'Cinzel', serif; font-size: .75rem; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase;
    color: #1a1a2e;
    background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
    border: none; border-radius: 8px; padding: .65rem 1rem;
    cursor: pointer; width: 100%;
    box-shadow: 0 3px 10px rgba(201,168,76,.35), inset 0 1px 0 rgba(255,255,255,.4);
    transition: transform .12s, box-shadow .12s, opacity .2s;
    position: relative; overflow: hidden;
  }
  .btn-coin-flip::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(135deg, rgba(255,255,255,.22) 0%, transparent 60%);
    pointer-events: none;
  }
  .btn-coin-flip:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 5px 16px rgba(201,168,76,.4), inset 0 1px 0 rgba(255,255,255,.4);
  }
  .btn-coin-flip:active:not(:disabled) { transform: translateY(0); }
  .btn-coin-flip:disabled { opacity: .5; cursor: not-allowed; }

  .coin-result-wrap { width: 100%; text-align: center; }

  .coin-result-banner {
    font-family: 'Cinzel', serif; font-size: 1rem; font-weight: 700;
    letter-spacing: .12em; text-transform: uppercase;
    opacity: 0; transform: translateY(5px);
    transition: opacity .3s, transform .3s;
    min-height: 1.3rem; line-height: 1.3;
  }
  .coin-result-banner.visible { opacity: 1; transform: translateY(0); }
  .coin-result-banner.pass { color: var(--pass-grn); }
  .coin-result-banner.fail { color: var(--fail-red); }

  .coin-result-sub {
    font-size: .7rem; font-weight: 300; color: #9a8a5a;
    letter-spacing: .04em; line-height: 1.4;
    opacity: 0; transition: opacity .3s .15s;
    min-height: 1rem; margin-top: 3px;
  }
  .coin-result-sub.visible { opacity: 1; }

  /* Right column — coin */
  .coin-right {
    flex-shrink: 0;
    width: 130px; height: 130px;
    position: relative;
  }

  .coin-mini {
    width: 100%; height: 100%;
    position: relative;
  }
  .face-mini {
    position: absolute; inset: 0;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
  }
  .face-mini::before {
    content: ''; position: absolute; inset: 4px;
    border-radius: 50%; border: 2px solid rgba(255,255,255,.18);
    pointer-events: none; z-index: 1;
  }
  .face-mini-mystery {
    background: radial-gradient(circle at 38% 32%, #e2bc6a, var(--gold) 55%, var(--gold-dim));
    box-shadow: inset 0 0 0 5px rgba(255,255,255,.15), 0 4px 18px rgba(201,168,76,.45);
  }
  .face-mini-fail {
    background: #000;
    box-shadow: 0 4px 18px rgba(192,57,43,.45);
  }
  .face-mini-pass {
    background: #000;
    box-shadow: 0 4px 18px rgba(39,174,96,.45);
  }
  .face-mini img {
    width: 100%; height: 100%;
    object-fit: cover; border-radius: 50%;
    position: relative; z-index: 2;
    display: block;
  }
  .face-mini svg { width: 100%; height: 100%; position: relative; z-index: 2; }

  @keyframes coinFlipMini {
    0%   { transform: scaleX(1); }
    50%  { transform: scaleX(0); }
    100% { transform: scaleX(1); }
  }
  .coin-mini.spinning {
    animation: coinFlipMini var(--half-dur, .18s) ease-in-out var(--flip-count, 7) forwards;
  }
  @keyframes wobbleMini {
    0%   { transform: scaleX(1) rotateZ(0deg); }
    20%  { transform: scaleX(1) rotateZ(2deg); }
    40%  { transform: scaleX(1) rotateZ(-1.5deg); }
    60%  { transform: scaleX(1) rotateZ(1deg); }
    80%  { transform: scaleX(1) rotateZ(-.5deg); }
    100% { transform: scaleX(1) rotateZ(0deg); }
  }
  .coin-mini.wobbling { animation: wobbleMini .45s ease-out forwards; }

  #coin-confetti {
    position: fixed; top: 0; left: 0;
    width: 100%; height: 100%;
    pointer-events: none; z-index: 9999;
  }

  /* ─────────────────────────────────────────
     CHARACTER GENERATOR
  ───────────────────────────────────────── */

  /* Category button row — single-line segmented control */
  /* ── Inline full chargen card ─────────────────── */
  .cg-fields {
    display: flex; flex-direction: column;
    padding: 10px 12px 4px;
    gap: 0;
  }
  .cg-field-row {
    display: flex; align-items: baseline;
    justify-content: space-between; gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
  }
  .cg-field-row:last-child { border-bottom: none; }
  .cg-field-text { flex: 1; min-width: 0; }
  .cg-field-label {
    font-family: 'Cinzel', serif; font-size: .5rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase;
    line-height: 1.2; margin-bottom: 1px;
  }
  .cg-field-value {
    font-size: .8rem; color: var(--ink); line-height: 1.35;
    transition: opacity .18s; min-height: 1rem;
  }
  .cg-field-value.fading { opacity: 0; }
  .cg-reroll-btn {
    flex-shrink: 0; align-self: center;
    font-size: .55rem; color: var(--muted);
    background: none; border: 1px solid var(--border); border-radius: 5px;
    padding: 3px 6px; cursor: pointer;
    transition: border-color .15s, color .15s; white-space: nowrap;
  }
  .cg-reroll-btn:hover:not(:disabled) { border-color: var(--gold); color: var(--gold-dim); }
  .cg-reroll-btn:disabled { opacity: .3; cursor: not-allowed; }
  .cg-footer {
    padding: 8px 12px 10px;
    display: flex; flex-direction: column; align-items: center; gap: 6px;
  }
  .cg-roll-btn {
    width: 100%;
    background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
    color: #1a1a2e; border: none;
    border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 700;
    letter-spacing: .08em; cursor: pointer;
    box-shadow: 0 3px 10px rgba(201,168,76,.35), inset 0 1px 0 rgba(255,255,255,.3);
    transition: opacity .2s, transform .1s;
  }
  .cg-roll-btn:hover:not(:disabled) { opacity: .88; }
  .cg-roll-btn:active { transform: scale(.98); }
  .cg-roll-btn:disabled { opacity: .35; cursor: not-allowed; }

  .cg-quick-cats {
    display: flex; gap: 0; padding: 8px 12px 0;
  }
  .cg-quick-cat-btn {
    flex: 1; font-family: 'Cinzel', serif;
    font-size: .58rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ink); background: var(--parchment);
    border: 1.5px solid var(--border); border-right: none; border-radius: 0;
    padding: 7px 2px; text-align: center; cursor: pointer;
    transition: border-color .18s, background .18s, color .18s;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .cg-quick-cat-btn:first-child { border-radius: 8px 0 0 8px; }
  .cg-quick-cat-btn:last-child  { border-right: 1.5px solid var(--border); border-radius: 0 8px 8px 0; }
  .cg-quick-cat-btn:hover:not(.active) { background: var(--gold-bg); border-color: var(--gold); color: var(--gold-dim); z-index: 1; }
  .cg-quick-cat-btn.active { background: var(--gold); border-color: var(--gold); border-right: 1.5px solid var(--gold); color: var(--ink); z-index: 1; }

  .cg-quick-result {
    padding: 10px 14px 8px;
    min-height: 52px; display: flex; flex-direction: column; justify-content: center; gap: 2px;
  }
  .cg-quick-result-label {
    font-family: 'Cinzel', serif; font-size: .54rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase;
    min-height: .85rem; opacity: 0; transition: opacity .2s;
  }
  .cg-quick-result-label.visible { opacity: 1; }
  .cg-quick-result-value {
    font-size: .9rem; color: var(--ink); line-height: 1.4;
    opacity: 0; transform: translateY(4px);
    transition: opacity .25s, transform .25s; min-height: 1.2rem;
  }
  .cg-quick-result-value.visible { opacity: 1; transform: translateY(0); }
  .cg-quick-result-value.fading  { opacity: 0; transform: translateY(4px); }
  .cg-mode-toggle {
    background: none; border: 1px solid var(--border); border-radius: 8px;
    padding: 7px 14px; width: 100%;
    font-family: 'Cinzel', serif; font-size: .72rem; font-weight: 600;
    letter-spacing: .07em; color: var(--muted);
    cursor: pointer; transition: border-color .15s, color .15s;
  }
  .cg-mode-toggle:hover { border-color: var(--gold); color: var(--gold-dim); }

  /* ─────────────────────────────────────────
     LOOT TABLE
  ───────────────────────────────────────── */

  .loot-wide {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 12px 12px 0;
  }

  .loot-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }

  .loot-item-name-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase; margin-bottom: 1px;
  }
  .loot-item-name {
    font-family: 'Cinzel', serif; font-size: 1rem; font-weight: 700;
    color: var(--ink); line-height: 1.25;
    transition: opacity .15s;
  }
  .loot-item-name.fading { opacity: 0; }

  .loot-divider { height: 1px; background: linear-gradient(90deg, var(--border), transparent); }

  .loot-item-flavour-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase; margin-bottom: 1px;
  }
  .loot-item-flavour {
    font-size: .82rem; font-weight: 300;
    color: var(--ink); font-style: italic; line-height: 1.5;
    transition: opacity .15s;
  }
  .loot-item-flavour.fading { opacity: 0; }

  .loot-image-slot {
    width: 100%;
    min-height: 60px;
    border-radius: 10px;
    background: linear-gradient(135deg, #1a1400, #2a2000);
    border: 1px solid var(--border);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
  }
  .loot-image-slot img { max-width: 100%; height: auto; display: block; border-radius: 10px; }
  .loot-slot-icon { font-size: 1.5rem; opacity: .45; }

  .loot-footer {
    padding: 8px 12px 12px;
    display: flex; flex-direction: column; align-items: center; gap: 6px;
  }
  .btn-pull {
    width: 100%;
    background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
    color: #1a1a2e; border: none;
    border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 700;
    letter-spacing: .08em; cursor: pointer;
    box-shadow: 0 3px 10px rgba(201,168,76,.35), inset 0 1px 0 rgba(255,255,255,.3);
    transition: opacity .2s, transform .1s;
  }
  .btn-pull:hover { opacity: .88; }
  .btn-pull:active { transform: scale(.98); }

  /* ─────────────────────────────────────────
     POLL TOOL
  ───────────────────────────────────────── */

  .poll-section { padding: 12px 12px 14px; display: flex; flex-direction: column; gap: 10px; }

  .poll-question-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .14em; text-transform: uppercase; margin-bottom: 4px;
  }
  .poll-question-text {
    font-family: 'Cinzel', serif; font-size: .95rem; font-weight: 600; color: var(--ink); line-height: 1.35;
  }

  /* Compact 2-col vote options when 4+ */
  .vote-options { display: flex; flex-direction: column; gap: 6px; }
  .vote-btn {
    width: 100%; background: var(--parchment); border: 1.5px solid var(--border); border-radius: 9px;
    padding: 9px 12px;
    font-family: 'Cinzel', serif; font-size: .8rem; font-weight: 600; color: var(--ink);
    cursor: pointer; text-align: left; letter-spacing: .02em;
    transition: border-color .18s, background .18s, transform .1s;
    display: flex; align-items: center; gap: 9px;
  }
  .vote-btn .opt-letter { font-size: .62rem; font-weight: 700; letter-spacing: .1em; color: var(--gold); flex-shrink: 0; min-width: 14px; }
  .vote-btn:hover:not(:disabled) { border-color: var(--gold); background: var(--gold-bg); }
  .vote-btn:disabled { cursor: default; }

  .poll-result-wrap { display: flex; flex-direction: column; gap: 8px; }
  .poll-result-row { display: flex; flex-direction: column; gap: 3px; }
  .poll-result-label-row { display: flex; justify-content: space-between; align-items: baseline; }
  .poll-result-opt-name { font-family: 'Cinzel', serif; font-size: .72rem; font-weight: 600; color: var(--ink); }
  .poll-result-pct { font-family: 'Cinzel', serif; font-size: .8rem; font-weight: 700; color: var(--gold); }
  .poll-result-count { font-size: .6rem; color: var(--muted); margin-left: 4px; }
  .bar-track { height: 7px; background: var(--border); border-radius: 4px; overflow: hidden; }
  .bar-fill { height: 100%; border-radius: 4px; background: linear-gradient(90deg, var(--gold-dim), var(--gold)); transition: width .6s cubic-bezier(.22,1,.36,1); width: 0%; }
  .bar-fill.winner { background: linear-gradient(90deg, #1e8449, var(--pass-grn)); }

  .voted-chip { display: inline-flex; align-items: center; gap: 5px; font-size: .68rem; letter-spacing: .04em; text-transform: uppercase; color: var(--pass-grn); font-weight: 700; }
  .total-votes { font-size: .65rem; color: var(--muted); letter-spacing: .04em; text-align: center; }
  .poll-waiting { text-align: center; padding: 10px 0; font-size: .82rem; color: var(--muted); line-height: 1.5; }
  .poll-waiting-pulse { animation: waitPulse 2s ease-in-out infinite; display: inline-block; font-size: 1.2rem; margin-bottom: 4px; }
   50% { opacity: .4; } }
  .live-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--pass-grn); display: inline-block; animation: livePulse 1.4s ease-in-out infinite; margin-right: 4px; }
   50% { opacity: .25; } }

  .poll-footer {
    padding: 0 12px 12px;
    display: flex; flex-direction: column; align-items: center; gap: 6px;
  }
  .poll-status-line { font-size: .65rem; color: var(--muted); letter-spacing: .04em; text-align: center; }
  .poll-setup-notice { padding: 14px; text-align: center; }
  .poll-setup-notice .notice-icon { font-size: 1.6rem; margin-bottom: 6px; }
  .poll-setup-notice .notice-title { font-family: 'Cinzel', serif; font-size: .88rem; font-weight: 700; color: var(--ink); margin-bottom: 4px; }
  .poll-setup-notice .notice-body { font-size: .75rem; color: var(--muted); line-height: 1.55; }
  .poll-setup-notice a { color: var(--gold); text-decoration: none; border-bottom: 1px solid rgba(201,168,76,.35); }

  /* ─────────────────────────────────────────
     TRAIT GENERATOR
  ───────────────────────────────────────── */

  .trait-wide {
    display: flex;
    flex-direction: column;
    padding: 12px 12px 14px;
    gap: 10px;
  }

  .trait-display-label {
    font-family: 'Cinzel', serif; font-size: .58rem; font-weight: 600;
    color: var(--gold); letter-spacing: .16em; text-transform: uppercase;
  }
  .trait-big-value {
    font-family: 'Cinzel', serif; font-size: clamp(1rem, 3.5vw, 1.3rem); font-weight: 700;
    color: var(--ink); line-height: 1.35; letter-spacing: .02em;
    transition: opacity .2s; min-height: 1.5rem;
  }
  .trait-big-value.fading { opacity: 0; }
  .trait-source-tag { font-size: .62rem; color: var(--muted); letter-spacing: .07em; text-transform: uppercase; }
  .trait-loot-name { font-family: 'Cinzel', serif; font-size: 1rem; font-weight: 700; color: var(--ink); line-height: 1.25; }
  .trait-loot-flavour { font-size: .82rem; font-weight: 300; color: var(--muted); font-style: italic; line-height: 1.5; }

  .trait-footer {
    padding: 0 12px 12px;
    display: flex; flex-direction: column; align-items: center; gap: 6px;
  }
  .btn-draw-trait {
    width: 100%;
    background: linear-gradient(135deg, var(--gold) 0%, #e2bc6a 50%, var(--gold) 100%);
    color: #1a1a2e; border: none;
    border-radius: 8px; padding: 10px;
    font-family: 'Cinzel', serif; font-size: .82rem; font-weight: 700;
    letter-spacing: .08em; cursor: pointer;
    box-shadow: 0 3px 10px rgba(201,168,76,.35), inset 0 1px 0 rgba(255,255,255,.3);
    transition: opacity .2s, transform .1s;
  }
  .btn-draw-trait:hover:not(:disabled) { opacity: .88; }
  .btn-draw-trait:active { transform: scale(.98); }
  .btn-draw-trait:disabled { opacity: .35; cursor: not-allowed; }

  /* Mulligan pips (shared) */
  .mulligan-bar {
    display: flex; align-items: center; justify-content: center; gap: 5px;
    padding: 6px 12px 0;
    font-size: .65rem; color: var(--muted); letter-spacing: .06em; text-transform: uppercase;
  }
  .pip-row { display: flex; gap: 4px; }
  .pip { width: 7px; height: 7px; border-radius: 50%; background: var(--gold); transition: background .3s, transform .2s; }
  .pip.spent { background: var(--border); transform: scale(.85); }

  .lock-bar {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    background: var(--border); border-radius: 8px; padding: 9px 12px; width: 100%;
  }
  .lock-bar .lock-msg { font-size: .75rem; color: var(--muted); }
  .lock-bar .lock-cd { font-family: 'Cinzel', serif; font-size: .85rem; font-weight: 600; color: var(--ink); white-space: nowrap; }

  /* ─────────────────────────────────────────
     COMING SOON
  ───────────────────────────────────────── */

  .section-rule { height: 1px; background: linear-gradient(90deg, transparent, var(--border) 20%, var(--border) 80%, transparent); margin: .2rem 0 .75rem; }
  .section-label { font-family: 'Cinzel', serif; font-size: .55rem; font-weight: 600; letter-spacing: .22em; text-transform: uppercase; color: var(--gold-dim); margin-bottom: .5rem; }

  .soon-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .soon-card {
    background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px;
    padding: 10px 12px; display: flex; flex-direction: column; gap: 3px;
    opacity: .52; cursor: default;
    animation: slideUp .4s cubic-bezier(.22,1,.36,1) both; animation-delay: .3s;
  }
  .soon-icon { font-size: 1.1rem; line-height: 1; margin-bottom: 3px; }
  .soon-name { font-family: 'Cinzel', serif; font-size: .7rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ink); line-height: 1.2; }
  .soon-desc { font-size: .65rem; font-weight: 300; color: var(--muted); line-height: 1.35; }
  .soon-badge { display: inline-block; font-family: 'Cinzel', serif; font-size: .48rem; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); border: 1px solid var(--border); border-radius: 20px; padding: 2px 7px; margin-top: 3px; align-self: flex-start; }

  footer { text-align: center; padding-bottom: 1rem; border-top: none; font-size: .58rem; color: var(--muted); letter-spacing: .08em; text-transform: uppercase; background: transparent; }

  /* ── QR Code shelf ── */
  .qr-wrap { display: flex; flex-direction: column; align-items: center; padding: 16px 16px 14px; gap: 10px; }
  .qr-img { width: 100%; max-width: 280px; max-height: 58vh; object-fit: contain; border-radius: 12px; cursor: pointer; display: block; }
  .qr-hint { font-size: .72rem; color: var(--muted); text-align: center; line-height: 1.5; margin: 0; }


  /* @keyframes slideUp comes from styles.css */
