    /* ==========================================================
       GLOBAL
    ========================================================== */

    :root {
      --bg: #070b12;
      --panel: rgba(18, 25, 38, 0.88);

      --border: rgba(255, 255, 255, 0.08);
      --border-hover: rgba(255, 255, 255, 0.18);

      --text: #f5f7fb;
      --text-soft: #9ca8ba;
      --text-muted: #687487;

      --gold: #d5b264;
      --gold-light: #f3db91;

      /* THE SIX MANA COLOURS

         Each colour is two values, not one:

         --fill-*   the orb itself. Pulled from the printed
                    pips and card frames, so black is actually
                    black and white is actually white.

         --mana-*   the accent: text, borders, bars, particles.
                    Must stay legible on the dark panel, which
                    is why black's accent is gunmetal silver
                    rather than black. Using the fill here
                    would make black mana invisible.
      */

      --fill-white: #fffdf4;
      --fill-blue: #1276c9;
      --fill-black: #0a0a0e;
      --fill-red: #cf3520;
      --fill-green: #1a8449;
      --fill-colorless: #aab3bf;

      --mana-white: #fffdf2;
      --mana-blue: #4fa8f0;
      --mana-black: #b3aebb;
      --mana-red: #ff6446;
      --mana-green: #45c179;
      --mana-colorless: #c2cad6;

      --radius-large: 24px;
      --radius-medium: 18px;

      --shadow: 0 25px 70px rgba(0, 0, 0, 0.35);

      --reel-digit: 66px;
    }

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

    html {
      scroll-behavior: smooth;
    }

    body {
      min-height: 100vh;
      font-family: "Inter", sans-serif;
      color: var(--text);

      background:
        radial-gradient(circle at 15% 10%, rgba(79, 89, 255, 0.12), transparent 30%),
        radial-gradient(circle at 85% 20%, rgba(38, 182, 255, 0.08), transparent 25%),
        radial-gradient(circle at 50% 100%, rgba(213, 178, 100, 0.06), transparent 30%),
        var(--bg);
    }

    /* position:fixed is what actually holds the page on iOS */
    body.rw-locked {
      position: fixed;
      width: 100%;
      overflow: hidden;
    }

    button {
      font-family: inherit;
    }

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

    .app {
      width: min(1180px, calc(100% - 32px));
      margin: 0 auto;
      padding: 26px 0 70px;
    }

    /* ==========================================================
       HEADER

       Deliberately almost nothing: the store crest in the hero
       already says whose tower this is.
    ========================================================== */

    .topbar {
      display: flex;
      justify-content: flex-end;

      margin-bottom: 14px;
    }

    .icon-button {
      width: 43px;
      height: 43px;

      display: grid;
      place-items: center;

      border-radius: 50%;
      border: 1px solid var(--border);
      background: rgba(255,255,255,0.025);
      color: var(--text-soft);

      cursor: pointer;

      transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
    }

    .icon-button:hover {
      transform: translateY(-2px);
      border-color: var(--border-hover);
      background: rgba(255,255,255,0.06);
    }

    /* ==========================================================
       PLAYER HERO
    ========================================================== */

    .player-card {
      position: relative;
      overflow: hidden;

      padding: 36px;

      background: linear-gradient(135deg, rgba(23, 31, 47, 0.96), rgba(10, 15, 24, 0.96));

      border: 1px solid var(--border);
      border-radius: var(--radius-large);

      box-shadow: var(--shadow);
    }

    .player-card::before {
      content: "";
      position: absolute;

      width: 500px;
      height: 500px;
      top: -330px;
      right: -120px;

      border-radius: 50%;

      background: radial-gradient(circle, rgba(100, 111, 255, 0.22), transparent 65%);

      pointer-events: none;
    }

    .player-top {
      position: relative;
      z-index: 2;

      display: flex;
      align-items: flex-start;
      justify-content: space-between;
      gap: 30px;
    }

    .welcome {
      color: var(--gold);
      font-size: 12px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 3px;
      margin-bottom: 9px;
    }

    .username {
      font-family: "Cinzel", serif;
      font-size: clamp(30px, 5vw, 50px);
      line-height: 1;
      font-weight: 700;
      letter-spacing: 1px;
    }

    .player-title {
      margin-top: 12px;

      display: inline-flex;
      align-items: center;
      gap: 12px;

      font-family: "Cinzel", serif;
      font-size: clamp(15px, 2.4vw, 20px);
      font-weight: 600;
      letter-spacing: 1.4px;

      background: linear-gradient(120deg, var(--gold-light), var(--gold) 55%, #a5813a);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;

      filter: drop-shadow(0 0 16px rgba(213, 178, 100, 0.35));
    }

    /* thin gold rules either side, like an engraved plate */
    .player-title::before,
    .player-title::after {
      content: "";

      width: clamp(18px, 5vw, 42px);
      height: 1px;

      background: linear-gradient(90deg, transparent, var(--gold));
    }

    .player-title::after {
      background: linear-gradient(90deg, var(--gold), transparent);
    }

    .player-title:empty {
      display: none;
    }

    .player-description {
      max-width: 560px;
      margin-top: 14px;

      color: var(--text-soft);

      font-size: 14px;
      line-height: 1.6;
    }

    /* ---- store logo, where the player level badge used to be ---- */

    .store-logo {
      flex: 0 0 auto;

      width: 118px;
      height: 118px;

      display: block;

      object-fit: cover;

      border-radius: 20px;
      border: 1px solid rgba(213, 178, 100, 0.35);

      box-shadow:
        0 14px 40px rgba(0, 0, 0, 0.45),
        0 0 34px rgba(86, 162, 255, 0.16);
    }

    /* ==========================================================
       MANA POOL
    ========================================================== */

    .pool {
      position: relative;
      z-index: 2;

      margin-top: 22px;
    }

    .pool-heading {
      display: flex;
      align-items: baseline;
      justify-content: space-between;
      gap: 16px;

      margin-bottom: 9px;
    }

    .pool-label {
      color: var(--text-soft);
      font-size: 11px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 2px;
    }

    .pool-note {
      color: var(--text-muted);
      font-size: 11px;
    }

    /* six across, always — the pool is a single glanceable row */
    .pool-grid {
      display: grid;
      grid-template-columns: repeat(6, 1fr);
      gap: 8px;
    }

    .mana-tile {
      padding: 12px 6px;

      display: block;
      width: 100%;

      text-align: center;

      color: inherit;
      font-family: inherit;

      background: rgba(255,255,255,0.025);

      border: 1px solid var(--border);
      border-radius: 14px;

      cursor: pointer;

      transition:
        transform 0.2s ease,
        border-color 0.3s ease,
        background 0.2s ease,
        box-shadow 0.3s ease;
    }

    .mana-tile:hover {
      transform: translateY(-2px);
      background: rgba(255,255,255,0.05);
      border-color: var(--pip);
      box-shadow: 0 0 20px var(--pip-glow);
    }

    .mana-pip {
      width: 20px;
      height: 20px;

      margin: 0 auto 7px;

      border-radius: 50%;

      /* the orb uses --pip-fill; a rim keeps the black orb
         from disappearing into the dark panel */
      background:
        radial-gradient(circle at 33% 27%, rgba(255,255,255,0.55), transparent 52%),
        var(--pip-fill, var(--pip));

      box-shadow:
        0 0 12px var(--pip-glow),
        inset 0 0 0 1px rgba(255,255,255,0.22),
        inset 0 -3px 7px rgba(0,0,0,0.45);
    }

    .mana-balance {
      font-size: 18px;
      font-weight: 800;
      line-height: 1;
    }

    .mana-name {
      margin-top: 5px;

      color: var(--text-muted);

      font-size: 8.5px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1px;
    }

    .mana-lifetime {
      margin-top: 3px;

      color: var(--text-muted);

      font-size: 9px;
      letter-spacing: 0.2px;
    }

    /* ==========================================================
       NEXT SPELL NUDGE
    ========================================================== */

    .nudge {
      position: relative;
      z-index: 2;

      display: flex;
      align-items: center;
      gap: 10px;

      margin-top: 12px;
      padding: 10px 15px;

      background: rgba(213, 178, 100, 0.055);

      border: 1px solid rgba(213, 178, 100, 0.22);
      border-radius: 13px;
    }

    .nudge-icon {
      flex: 0 0 auto;
      font-size: 14px;
    }

    .nudge-text {
      font-size: 12px;
      line-height: 1.45;
      color: var(--text-soft);
    }

    .nudge-text strong {
      color: var(--gold-light);
      font-weight: 800;
    }

    /* ==========================================================
       SUMMARY STATS
    ========================================================== */

    /* three across, always — one line, never a stack */
    .stats {
      position: relative;
      z-index: 2;

      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 10px;

      margin-top: 12px;
    }

    .stat {
      padding: 12px 14px;

      text-align: center;

      /* this one is a <button> so it can scroll to the
         collection — without these it inherits the browser's
         black button text instead of the page's */
      color: var(--text);
      font-family: inherit;

      background: rgba(255,255,255,0.025);

      border: 1px solid var(--border);
      border-radius: 14px;
    }

    .stat-value {
      color: var(--text);

      font-size: 19px;
      font-weight: 800;
      line-height: 1.1;
    }

    .stat.is-jump {
      cursor: pointer;

      transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
    }

    .stat.is-jump:hover {
      transform: translateY(-2px);
      border-color: rgba(213, 178, 100, 0.4);
      background: rgba(255, 255, 255, 0.05);
    }

    .stat-label {
      margin-top: 3px;

      color: var(--text-muted);

      font-size: 9px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.2px;
    }

    /* ==========================================================
       SECTION
    ========================================================== */

    .section {
      margin-top: 34px;
    }

    .section-heading {
      display: flex;
      align-items: end;
      justify-content: space-between;
      gap: 20px;

      margin-bottom: 18px;
    }

    .section-eyebrow {
      color: var(--gold);

      font-size: 10px;
      font-weight: 700;
      letter-spacing: 3px;
      text-transform: uppercase;

      margin-bottom: 5px;
    }

    .section-title {
      font-family: "Cinzel", serif;
      font-size: 25px;
      font-weight: 600;
    }

    .section-description {
      color: var(--text-muted);
      font-size: 12px;
      max-width: 380px;
      text-align: right;
    }

    /* ==========================================================
       SPELLBOOK
    ========================================================== */

    .spell-tabs {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;

      margin-bottom: 16px;
    }

    .spell-tab {
      display: flex;
      align-items: center;
      gap: 8px;

      padding: 9px 15px;

      color: var(--text-soft);
      background: rgba(255,255,255,0.025);

      border: 1px solid var(--border);
      border-radius: 100px;

      font-size: 11px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.4px;

      cursor: pointer;

      transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
    }

    .spell-tab:hover {
      border-color: var(--border-hover);
      color: var(--text);
    }

    .spell-tab[aria-selected="true"] {
      color: var(--text);
      background: rgba(255,255,255,0.06);
      border-color: var(--tab-color);
      box-shadow: 0 0 18px var(--tab-glow);
    }

    .spell-tab .mana-pip {
      width: 14px;
      height: 14px;
      margin: 0;
    }

    /* TWO SPELLS TO A ROW, ONE LINE EACH

         Name — flavour ......... [ CAST (50) (10) ] (2)

       The cost lives inside the button, exactly as it does in
       the modal, so the button IS the cost and nothing is read
       twice. Two columns halve the scrolling.
    */

    .spellbook {
      display: grid;

      /* minmax(0, …) not 1fr: a nowrap flavour would otherwise
         set the column's minimum width and the two columns
         would come out uneven */
      grid-template-columns: repeat(2, minmax(0, 1fr));

      gap: 10px;

      background: none;
      border: none;
    }

    .spell {
      display: flex;
      align-items: center;
      gap: 12px;

      padding: 10px 12px 10px 15px;

      background:
        linear-gradient(145deg, rgba(20, 28, 42, 0.95), rgba(11, 16, 25, 0.95));

      border: 1px solid var(--border);
      border-radius: 14px;
    }

    .spell.is-locked {
      background: rgba(0, 0, 0, 0.2);
    }

    .spell.is-locked .spell-name {
      opacity: 0.72;
    }

    /* cast before: a coloured spine down the left edge */

    .spell.is-known {
      border-color: var(--pip-glow);
      box-shadow: inset 3px 0 0 var(--pip);
    }

    .spell-main {
      flex: 1;
      min-width: 0;

      /* the flavour trims rather than wrapping — the whole
         line is in the modal anyway */
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .spell-name {
      font-family: "Cinzel", serif;
      font-size: 15px;
      font-weight: 600;
    }

    .spell-flavour {
      color: var(--text-muted);

      font-size: 11.5px;
      font-style: italic;
    }

    /* when a spell cannot be paid for, what is missing is more
       use than the flavour, so it takes the same slot */

    .spell-short {
      color: var(--gold);

      font-size: 11px;
      font-weight: 700;
    }

    .spell-actions {
      flex: 0 0 auto;

      display: flex;
      align-items: center;
      gap: 7px;
    }

    /* an orb with its number beside it, the way a cost reads */

    .cost {
      display: inline-flex;
      align-items: center;
      gap: 5px;

      /* keeps the button from growing taller than its text */
      line-height: 1;

      font-size: 13px;
      font-weight: 800;

      color: var(--text);
    }

    .mana-pip.is-inline {
      width: 16px;
      height: 16px;
      margin: 0;
      flex: 0 0 auto;
    }

    .spell-casts {
      flex: 0 0 auto;

      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 5px;

      padding: 8px 11px;

      color: var(--pip);
      background: rgba(255, 255, 255, 0.04);

      border: 1px solid var(--pip);
      border-radius: 10px;

      font-family: inherit;
      font-size: 11px;
      font-weight: 800;

      cursor: pointer;

      transition: background 0.2s ease, transform 0.2s ease;
    }

    .spell-casts:hover {
      transform: translateY(-1px);
      background: rgba(255, 255, 255, 0.09);
    }

    /* THE CALL TO ACTION

       One button style, used in the spellbook row and in the
       modal, so a player recognises it as the same action in
       both places. */

    .sp-cast {
      position: relative;
      z-index: 2;

      text-decoration: none;

      display: flex;
      align-items: center;
      justify-content: center;
      gap: 9px;

      flex: 0 0 auto;

      padding: 8px 13px;

      color: #120d02;
      background: linear-gradient(145deg, var(--gold-light), var(--gold));

      border: none;
      border-radius: 10px;

      font-family: inherit;
      font-size: 11px;
      font-weight: 800;
      text-transform: uppercase;
      letter-spacing: 1.2px;

      cursor: pointer;

      transition: transform 0.2s ease, box-shadow 0.2s ease;
    }

    .sp-cast:hover:not(:disabled) {
      transform: translateY(-2px);
      box-shadow: 0 10px 26px rgba(213, 178, 100, 0.3);
    }

    /* unaffordable: same shape, no gold. Still clickable, since
       it opens the spell rather than casting it. */

    .sp-cast.is-locked {
      color: var(--text-soft);
      background: rgba(255, 255, 255, 0.045);
      border: 1px solid var(--border);
    }

    .sp-cast.is-locked:hover {
      color: var(--text);
      border-color: var(--border-hover);
      box-shadow: none;
    }

    .sp-cast:disabled {
      color: var(--text-muted);
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid var(--border);
      cursor: not-allowed;
    }

    /* the orbs sit inside the button */

    .sp-cast .cost {
      color: inherit;
      font-size: 12.5px;
      letter-spacing: 0;
    }

    .sp-cast .mana-pip {
      box-shadow:
        inset 0 0 0 1px rgba(0,0,0,0.28),
        inset 0 -3px 7px rgba(0,0,0,0.4);
    }

    .sp-cast.is-locked .mana-pip {
      box-shadow:
        inset 0 0 0 1px rgba(255,255,255,0.2),
        inset 0 -3px 7px rgba(0,0,0,0.45);
    }

    /* in the modal it spans the dialog */

    .sp-cast.is-block {
      width: 100%;
      margin-top: 20px;
      padding: 15px 20px;
      font-size: 12px;
      letter-spacing: 1.4px;
    }

    /* ==========================================================
       TRIBE GRID
    ========================================================== */

    /* ==========================================================
       THE COLLECTION

       Every tribe is listed. An uncollected one is a tinted
       silhouette — you can see the shape of what you are
       missing, but not the artwork.
    ========================================================== */

    .tribe-grid {
      display: block;
    }

    .collection-summary {
      margin-bottom: 14px;
      padding: 12px 16px;

      background:
        linear-gradient(90deg, var(--pip-glow), transparent 55%);

      border: 1px solid var(--border);
      border-left: 3px solid var(--pip);
      border-radius: 12px;
    }

    .collection-line {
      color: var(--text-soft);
      font-size: 13px;
    }

    .collection-line strong {
      color: var(--text);
      font-weight: 800;
    }

    .collection-bonus {
      display: inline-block;
      margin-left: 8px;
      padding: 3px 10px;

      color: var(--gold-light);
      background: rgba(213, 178, 100, 0.08);

      border: 1px solid rgba(213, 178, 100, 0.25);
      border-radius: 100px;

      font-size: 10.5px;
      font-weight: 800;
    }

    .collection-note {
      margin-top: 5px;
      color: var(--text-muted);
      font-size: 11px;
    }

    .tribe-chips {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
      gap: 9px;
    }

    .tribe-chip {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;

      padding: 13px 8px;

      color: inherit;
      font-family: inherit;
      text-align: center;

      background: rgba(255, 255, 255, 0.022);

      border: 1px solid var(--border);
      border-radius: 14px;

      cursor: pointer;

      transition:
        transform 0.2s ease,
        border-color 0.2s ease,
        background 0.2s ease;
    }

    .tribe-chip:hover {
      transform: translateY(-3px);
      border-color: var(--pip);
      background: rgba(255, 255, 255, 0.05);
    }

    .tribe-chip:focus-visible {
      outline: 2px solid var(--gold);
      outline-offset: 2px;
    }

    .tribe-chip.is-collected {
      background:
        linear-gradient(160deg, var(--pip-glow), rgba(255,255,255,0.02) 60%);
      border-color: var(--pip);
    }

    .tribe-face {
      position: relative;

      width: 54px;
      height: 54px;

      display: grid;
      place-items: center;

      overflow: hidden;

      border-radius: 13px;

      background: rgba(255, 255, 255, 0.04);
      border: 1px solid var(--border);
    }

    .tribe-chip.is-collected .tribe-face {
      border-color: var(--pip);
      box-shadow: 0 0 16px var(--pip-glow);
    }

    .tribe-glyph {
      font-size: 26px;
      line-height: 1;
    }

    /*
       THE SILHOUETTE

       Transparent text with a zero-blur text-shadow repaints an
       emoji as one flat shape. Tinted to the tribe's mana colour
       it reads as a shadow of the tribe — no artwork files are
       needed for the locked state.
    */

    .tribe-glyph.is-silhouette {
      color: transparent;
      text-shadow: 0 0 0 var(--pip);
      opacity: 0.45;
      filter: blur(0.4px);
    }

    .tribe-lock {
      position: absolute;
      right: 4px;
      bottom: 2px;

      color: var(--text-muted);

      font-family: "Cinzel", serif;
      font-size: 13px;
      font-weight: 700;
    }

    .tribe-art {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }

    .tribe-pips {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 3px;

      display: flex;
      justify-content: center;
      gap: 2px;
    }

    .mana-pip.is-tiny {
      width: 7px;
      height: 7px;
      margin: 0;
    }

    .tribe-label {
      font-family: "Cinzel", serif;
      font-size: 12px;
      font-weight: 600;
      line-height: 1.25;
    }

    .tribe-chip:not(.is-collected) .tribe-label {
      color: var(--text-soft);
    }



    /* ---- the tribe modal ---- */

    .tribe-face.is-large {
      position: relative;
      z-index: 2;

      width: min(300px, 100%);
      height: clamp(130px, 24dvh, 200px);

      margin: 20px auto 0;

      border-radius: var(--radius-medium);
    }

    .tribe-face.is-large .tribe-glyph {
      font-size: clamp(60px, 12dvh, 92px);
    }

    .tribe-face.is-large .tribe-lock {
      right: 12px;
      bottom: 6px;
      font-size: 22px;
    }

    .tribe-face.is-revealed {
      border-color: var(--pip);
      box-shadow: 0 0 40px var(--pip-glow);
    }

    .tribe-pays {
      position: relative;
      z-index: 2;

      display: flex;
      align-items: center;
      justify-content: center;
      flex-wrap: wrap;
      gap: 10px;

      margin-top: 16px;
    }

    .tribe-pays-label,
    .tribe-pays-note {
      color: var(--text-muted);

      font-size: 10px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.4px;
    }

    .tribe-stats {
      position: relative;
      z-index: 2;

      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 10px;

      margin-top: 16px;
    }

    .tribe-stats[hidden] { display: none; }

    .tribe-stat {
      padding: 11px;

      background: rgba(255,255,255,0.03);
      border: 1px solid var(--border);
      border-radius: 12px;
    }

    .tribe-stat-value {
      font-size: 18px;
      font-weight: 800;
    }

    .tribe-stat-label {
      margin-top: 2px;

      color: var(--text-muted);

      font-size: 9px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.2px;
    }

    /* ==========================================================
       THE COLLECTION, CHANGING

       These play after the modal closes, once the page has
       scrolled to the tribe. The point is that the player sees
       the silhouette BECOME the artwork, rather than arriving
       to find it already changed.
    ========================================================== */

    /* first time collected: the shape turns and colours in */

    @keyframes tribe-reveal {
      0% {
        transform: rotateY(-90deg) scale(0.9);
        filter: grayscale(1) brightness(0.45);
      }
      55% {
        filter: grayscale(0.3) brightness(1.35);
      }
      100% {
        transform: rotateY(0) scale(1);
        filter: none;
      }
    }

    .tribe-chip.is-revealing .tribe-face {
      animation: tribe-reveal 1.2s cubic-bezier(.2,.8,.3,1) both;
    }

    /* a glint sweeps across whatever just changed */

    @keyframes tribe-glint {
      0% { transform: translateX(-130%) skewX(-18deg); opacity: 0; }
      35% { opacity: 1; }
      100% { transform: translateX(130%) skewX(-18deg); opacity: 0; }
    }

    .tribe-chip.is-revealing::after,
    .tribe-chip.is-ranking::after,
    .tribe-chip.is-tallying::after {
      content: "";

      position: absolute;
      inset: 0;
      z-index: 3;

      overflow: hidden;
      border-radius: inherit;

      background:
        linear-gradient(
          100deg,
          transparent 38%,
          rgba(255, 255, 255, 0.38) 50%,
          transparent 62%
        );

      pointer-events: none;

      animation: tribe-glint 1.1s ease-out 0.5s both;
    }

    /* the whole chip pulses in its mana colour */

    @keyframes tribe-chip-flare {
      0%, 100% {
        border-color: var(--pip);
        box-shadow: 0 0 0 rgba(0,0,0,0);
      }
      40% {
        border-color: var(--pip);
        box-shadow: 0 0 34px var(--pip), 0 0 60px var(--pip-glow);
      }
    }

    .tribe-chip.is-revealing,
    .tribe-chip.is-ranking {
      animation: tribe-chip-flare 1.6s ease-in-out 0.35s 2;
    }

    .tribe-chip.is-tallying {
      animation: tribe-chip-flare 1.4s ease-in-out 0.3s 1;
    }

    /* a rank climbing: the numeral swaps with a pop */

    @keyframes rank-swap {
      0% { transform: scale(0.4) rotate(-14deg); opacity: 0; }
      55% { transform: scale(1.45) rotate(4deg); opacity: 1; }
      100% { transform: scale(1) rotate(0); opacity: 1; }
    }

    .tribe-chip.is-ranking .tribe-rank,
    .tribe-chip.is-revealing .tribe-rank {
      animation: rank-swap 0.85s cubic-bezier(.2,.9,.3,1.4) both;
      box-shadow: 0 0 18px rgba(213, 178, 100, 0.75);
    }

    /* the badge waits for the artwork to finish turning */
    .tribe-chip.is-revealing .tribe-rank {
      animation-delay: 0.8s;
    }

    /* the rank badge on a tribe collected more than once */

    .tribe-rank {
      position: absolute;
      top: 7px;
      right: 8px;

      min-width: 19px;
      padding: 1px 4px;

      color: #120d02;
      background: linear-gradient(145deg, var(--gold-light), var(--gold));

      border-radius: 6px;

      font-family: "Cinzel", serif;
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 0.5px;
    }

    .tribe-chip { position: relative; }

    .tab-count {
      margin-left: 6px;
      opacity: 0.65;
      font-size: 9.5px;
    }

    .mana-pip.is-mixed {
      background:
        conic-gradient(
          var(--mana-white), var(--mana-blue), var(--mana-black),
          var(--mana-red), var(--mana-green), var(--mana-white)
        );
    }

    /* ==========================================================
       REWARD LANDING ANIMATIONS
    ========================================================== */

    @keyframes rw-card-flash {
      0%, 100% {
        border-color: var(--border);
        box-shadow: 0 0 0 rgba(213, 178, 100, 0);
      }
      30%, 55% {
        border-color: rgba(213, 178, 100, 0.65);
        box-shadow: 0 0 46px rgba(213, 178, 100, 0.3), 0 18px 45px rgba(0,0,0,0.22);
      }
    }

    .mana-tile.is-rewarded {
      animation: rw-card-flash 1.5s ease-in-out 2;
    }

    @keyframes rw-text-flash {
      0%, 100% { color: inherit; text-shadow: none; }
      35% { color: var(--gold-light); text-shadow: 0 0 18px rgba(213, 178, 100, 0.7); }
    }

    .is-counting {
      animation: rw-text-flash 1.4s ease-in-out 2;
      font-weight: 800;
    }

    @keyframes rw-spend-flash {
      0%, 100% { color: inherit; text-shadow: none; }
      35% { color: var(--mana-red); text-shadow: 0 0 18px rgba(255, 111, 82, 0.6); }
    }

    .is-spending {
      animation: rw-spend-flash 1.2s ease-in-out 2;
      font-weight: 800;
    }

    .progress-fill.is-surging {
      box-shadow: 0 0 30px var(--pip), 0 0 60px var(--pip-glow);
    }

    @keyframes rw-row-in {
      from { opacity: 0; transform: translateY(-10px); background: rgba(213,178,100,0.14); }
      to { opacity: 1; transform: translateY(0); background: transparent; }
    }

    .activity-item.is-new {
      animation: rw-row-in 1.1s ease both;
    }

    /* ==========================================================
       ACTIVITY
    ========================================================== */

    .activity-panel {
      overflow: hidden;

      background: var(--panel);

      border: 1px solid var(--border);
      border-radius: var(--radius-medium);
    }

    .activity-item {
      display: flex;
      align-items: center;
      gap: 14px;

      padding: 16px 19px;

      border-bottom: 1px solid var(--border);
    }

    .activity-item:last-child {
      border-bottom: none;
    }

    .activity-icon {
      width: 42px;
      height: 42px;
      flex: 0 0 auto;

      display: grid;
      place-items: center;

      background: rgba(255,255,255,0.04);
      border-radius: 12px;

      font-size: 20px;
    }

    .activity-main {
      flex: 1;
      min-width: 0;
    }

    .activity-title {
      font-size: 13px;
      font-weight: 700;
    }

    .activity-date {
      margin-top: 3px;
      color: var(--text-muted);
      font-size: 10px;
    }

    .activity-amount {
      flex: 0 0 auto;

      display: flex;
      align-items: center;
      gap: 7px;

      color: var(--pip);

      font-weight: 800;
      font-size: 13px;
    }

    .activity-amount .mana-pip {
      width: 13px;
      height: 13px;
      margin: 0;
    }

    .activity-amount.is-spend {
      color: var(--text-muted);
    }

    /* ==========================================================
       TEST BUTTONS
    ========================================================== */

    .test-area {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
      gap: 10px;

      margin-top: 45px;
    }

    .test-button {
      border: 1px solid rgba(213,178,100,0.28);
      border-radius: 12px;

      padding: 11px 18px;

      color: var(--gold-light);
      background: rgba(213,178,100,0.06);

      font-weight: 700;
      font-size: 11px;

      cursor: pointer;

      transition: background 0.2s ease, transform 0.2s ease;
    }

    .test-button:hover {
      transform: translateY(-2px);
      background: rgba(213,178,100,0.12);
    }

    /* ==========================================================
       MANA POPUP
    ========================================================== */

    .xp-popup {
      position: fixed;
      left: 50%;
      bottom: 40px;

      transform: translate(-50%, 30px) scale(0.92);
      opacity: 0;

      padding: 13px 22px;

      border-radius: 100px;

      background: rgba(12, 18, 27, 0.96);
      border: 1px solid rgba(213,178,100,0.35);

      color: var(--gold-light);

      font-size: 13px;
      font-weight: 800;

      box-shadow: 0 15px 50px rgba(0,0,0,0.45);

      pointer-events: none;

      transition: opacity 0.3s ease, transform 0.3s ease;

      z-index: 100;
    }

    .xp-popup.show {
      opacity: 1;
      transform: translate(-50%, 0) scale(1);
    }

    footer {
      margin-top: 50px;
      text-align: center;
      color: var(--text-muted);
      font-size: 10px;
      letter-spacing: 1.2px;
    }

    /* ==========================================================
       ==========================================================
          MODALS  (.rw- prefix, shared by both dialogs)
       ==========================================================
    ========================================================== */

    .rw-overlay {
      position: fixed;
      inset: 0;
      z-index: 200;

      display: grid;
      place-items: center;

      padding: 14px;

      overflow: hidden;
      overscroll-behavior: contain;

      background: rgba(3, 6, 11, 0.72);

      backdrop-filter: blur(9px) saturate(0.85);
      -webkit-backdrop-filter: blur(9px) saturate(0.85);

      opacity: 0;
      transition: opacity 0.32s ease;
    }

    .rw-overlay[hidden] { display: none; }
    .rw-overlay.is-open { opacity: 1; }

    .rw-card {
      position: relative;

      width: min(520px, 100%);
      max-height: calc(100dvh - 28px);

      margin: auto;
      padding: 30px 30px 24px;

      overflow: hidden auto;
      overscroll-behavior: contain;

      text-align: center;

      background: linear-gradient(135deg, rgba(25, 33, 50, 0.98), rgba(9, 13, 21, 0.99));

      border: 1px solid rgba(213, 178, 100, 0.22);
      border-radius: var(--radius-large);

      box-shadow: 0 35px 90px rgba(0,0,0,0.6), 0 0 60px var(--pip-glow, rgba(155,107,255,0.09));

      transform: translateY(22px) scale(0.96);
      opacity: 0;

      transition: transform 0.42s cubic-bezier(.2,.9,.25,1), opacity 0.42s ease;
    }

    .rw-card:focus,
    .rw-card:focus-visible { outline: none; }

    .rw-overlay.is-open .rw-card {
      transform: translateY(0) scale(1);
      opacity: 1;
    }

    .rw-card::before {
      content: "";
      position: absolute;

      width: 460px;
      height: 460px;
      top: -260px;
      left: 50%;
      margin-left: -230px;

      border-radius: 50%;

      background: radial-gradient(circle, var(--pip-glow, rgba(155,107,255,0.26)), transparent 66%);

      pointer-events: none;
    }

    .rw-close {
      position: absolute;
      top: 14px;
      right: 14px;
      z-index: 4;

      width: 36px;
      height: 36px;

      display: grid;
      place-items: center;

      border-radius: 50%;
      border: 1px solid var(--border);
      background: rgba(255,255,255,0.03);
      color: var(--text-soft);

      font-size: 14px;
      cursor: pointer;

      transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
    }

    .rw-close:hover {
      color: var(--text);
      border-color: var(--border-hover);
      background: rgba(255,255,255,0.08);
    }

    .rw-head {
      position: relative;
      z-index: 2;
      padding: 0 30px;
    }

    .rw-eyebrow {
      color: var(--gold);
      font-size: 10px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 3px;
    }

    .rw-title {
      margin-top: 10px;

      font-family: "Cinzel", serif;
      font-size: clamp(24px, 5.5vw, 32px);
      font-weight: 700;
      line-height: 1.15;
    }

    .rw-sub {
      max-width: 380px;
      margin: 11px auto 0;

      color: var(--text-soft);
      font-size: 13px;
      line-height: 1.6;
    }

    .rw-receipt {
      position: relative;
      z-index: 2;

      margin-top: clamp(14px, 2.4dvh, 22px);
      padding: 2px 15px;

      text-align: left;

      background: rgba(255,255,255,0.025);
      border: 1px solid var(--border);
      border-radius: 15px;
    }

    .rw-receipt-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 14px;

      padding: 11px 0;

      border-bottom: 1px dashed rgba(255,255,255,0.07);
    }

    .rw-receipt-row:last-child { border-bottom: none; }

    .rw-receipt-row dt {
      flex: 0 0 auto;
      color: var(--text-muted);
      font-size: 10px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.5px;
    }

    .rw-receipt-row dd {
      text-align: right;
      font-size: 13px;
      font-weight: 600;
    }

    /* ---- mystery card ---- */

    .rw-stage {
      position: relative;
      z-index: 2;

      margin-top: clamp(14px, 2.8dvh, 26px);

      perspective: 1200px;
    }

    .rw-flip {
      display: block;

      width: min(330px, 100%);
      height: clamp(136px, 25dvh, 232px);

      margin: 0 auto;
      padding: 0;

      background: none;
      border: none;
      cursor: pointer;

      animation: rw-float 5s ease-in-out infinite;
    }

    .rw-flip[disabled] { cursor: default; }

    @keyframes rw-float {
      0%, 100% { transform: translateY(0); }
      50% { transform: translateY(-7px); }
    }

    .rw-flip-inner {
      position: relative;
      width: 100%;
      height: 100%;

      transform-style: preserve-3d;
      transition: transform 1.25s cubic-bezier(.24,.86,.22,1);
    }

    .rw-flip-inner.is-flipped { transform: rotateY(900deg); }

    .rw-flip-inner.is-instant {
      transition: none;
      transform: rotateY(180deg);
    }

    .rw-face {
      position: absolute;
      inset: 0;

      overflow: hidden;

      display: grid;
      place-items: center;

      border-radius: var(--radius-medium);

      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
    }

    .rw-face-front {
      background: linear-gradient(150deg, rgba(91, 47, 168, 0.55), rgba(14, 19, 30, 0.95) 62%);
      border: 1px solid rgba(213, 178, 100, 0.3);
      box-shadow: inset 0 0 60px rgba(155, 107, 255, 0.22), 0 18px 45px rgba(0,0,0,0.45);
    }

    .rw-mark {
      font-family: "Cinzel", serif;
      font-size: clamp(62px, 13dvh, 96px);
      font-weight: 700;
      line-height: 1;

      background: linear-gradient(170deg, var(--gold-light), var(--gold) 45%, #8d6f34);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;

      filter: drop-shadow(0 0 18px rgba(213, 178, 100, 0.45));
    }

    .rw-face-front::after {
      content: "";
      position: absolute;
      inset: -40%;

      background: linear-gradient(104deg, transparent 38%, rgba(255,255,255,0.34) 50%, transparent 62%);

      transform: translateX(-110%);
      animation: rw-glint 3.4s ease-in-out infinite;

      pointer-events: none;
    }

    @keyframes rw-glint {
      0% { transform: translateX(-110%); }
      55%, 100% { transform: translateX(110%); }
    }

    .rw-face-back {
      transform: rotateY(180deg);
      border: 1px solid rgba(155, 107, 255, 0.4);
      box-shadow: 0 18px 45px rgba(0,0,0,0.45), 0 0 45px rgba(155, 107, 255, 0.2);
    }

    .rw-face-back img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      display: block;
    }

    /* THE CREST

       The crest is square and the card is landscape, so it is
       constrained on BOTH axes and left to keep its own aspect
       ratio. Sizing on one axis only was what clipped the owl's
       feet: 82% of the width is taller than the card. */

    .rw-face-back.is-crest-face {
      display: block;

      background:
        linear-gradient(150deg, rgba(30, 40, 60, 0.9), rgba(10, 15, 24, 0.96));
    }

    /*
       Positioned rather than laid out.

       A percentage max-height cannot resolve inside a grid row
       that is itself sized by its content — the browser has no
       height to take a percentage OF, so the crest rendered at
       its natural 256px and the owl's feet were clipped.

       Absolute inset gives it a definite box to shrink into,
       and auto margins centre whatever is left over.
    */

    .rw-face-back img.is-crest {
      position: absolute;
      inset: 10px;

      width: auto;
      height: auto;

      max-width: calc(100% - 20px);
      max-height: calc(100% - 20px);

      margin: auto;

      border-radius: 12px;
      object-fit: contain;
    }

    /* ---- reveal ---- */

    .rw-reveal-zone {
      position: relative;
      z-index: 2;

      margin-top: clamp(14px, 2.6dvh, 24px);
      min-height: clamp(96px, 15dvh, 128px);

      display: grid;
      place-items: center;
    }

    .rw-cta {
      position: relative;
      overflow: hidden;

      max-width: 340px;
      padding: 15px 26px;

      color: #120d02;
      background: linear-gradient(145deg, var(--gold-light), var(--gold));

      border: none;
      border-radius: 100px;

      font-size: 13px;
      font-weight: 800;
      line-height: 1.35;

      cursor: pointer;

      box-shadow: 0 12px 34px rgba(213, 178, 100, 0.28);
      animation: rw-pulse 2.4s ease-in-out infinite;

      transition: transform 0.2s ease, opacity 0.25s ease;
    }

    .rw-cta:hover { transform: translateY(-2px); }

    .rw-cta::after {
      content: "";
      position: absolute;
      inset: 0;

      background: linear-gradient(104deg, transparent 40%, rgba(255,255,255,0.75) 50%, transparent 60%);

      transform: translateX(-110%);
      animation: rw-glint 2.8s ease-in-out infinite;
    }

    @keyframes rw-pulse {
      0%, 100% { box-shadow: 0 12px 34px rgba(213, 178, 100, 0.28); }
      50% { box-shadow: 0 12px 44px rgba(213, 178, 100, 0.5); }
    }

    .rw-cta.is-gone {
      opacity: 0;
      transform: translateY(8px);
      pointer-events: none;
    }

    .rw-result[hidden] { display: none; }

    .rw-reel {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 3px;

      font-family: "Cinzel", serif;

      /*
         Tied to the height of the reel window rather than set
         independently. Cinzel's line box runs about 1.4x its
         font size, so a 52px digit needs 73px of room — in a
         66px window the descender simply got cut off.
      */
      font-size: calc(var(--reel-digit) * 0.66);
      font-weight: 700;

      color: var(--gold-light);

      filter: drop-shadow(0 0 16px rgba(213, 178, 100, 0.3));
      transition: filter 0.5s ease;
    }

    .rw-reel.is-landed {
      filter: drop-shadow(0 0 26px rgba(213, 178, 100, 0.75));
    }

    .rw-reel-sign {
      margin-right: 4px;
      color: var(--gold);
    }

    .rw-reel-col {
      position: relative;

      width: 44px;
      height: var(--reel-digit);

      overflow: hidden;

      background: rgba(255,255,255,0.03);
      border: 1px solid rgba(213, 178, 100, 0.2);
      border-radius: 10px;
    }

    .rw-reel-col::after {
      content: "";
      position: absolute;
      inset: 0;
      z-index: 2;

      background: linear-gradient(rgba(11,16,25,0.95), transparent 32%, transparent 68%, rgba(11,16,25,0.95));

      pointer-events: none;
    }

    .rw-reel-strip {
      display: flex;
      flex-direction: column;
      will-change: transform;
    }

    .rw-reel-strip span {
      display: grid;
      place-items: center;

      height: var(--reel-digit);
      flex: 0 0 var(--reel-digit);

      /* the glyph box must not exceed its slot, or digits clip
         as they scroll past */
      line-height: 1;
    }

    .rw-mana-label {
      margin-top: 14px;

      display: flex;
      align-items: center;
      justify-content: center;
      gap: 10px;

      font-family: "Cinzel", serif;
      font-size: 21px;
      font-weight: 600;

      color: var(--pip);
      text-shadow: 0 0 22px var(--pip-glow);

      opacity: 0;
      transform: translateY(10px);

      transition: opacity 0.5s ease, transform 0.5s ease;
    }

    .rw-xp-note {
      margin-top: 8px;

      color: var(--text-muted);
      font-size: 11px;

      opacity: 0;
      transition: opacity 0.5s ease 0.15s;
    }

    .rw-result.is-landed .rw-mana-label,
    .rw-result.is-landed .rw-xp-note {
      opacity: 1;
      transform: translateY(0);
    }

    .rw-done {
      position: relative;
      z-index: 2;

      width: 100%;
      margin-top: clamp(14px, 2.6dvh, 24px);
      padding: 13px 20px;

      color: var(--gold-light);
      background: rgba(213, 178, 100, 0.06);

      border: 1px solid rgba(213, 178, 100, 0.28);
      border-radius: 12px;

      font-size: 11px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 1.6px;

      cursor: pointer;

      transition: background 0.2s ease, transform 0.2s ease;
    }

    .rw-done:hover:not(:disabled) {
      transform: translateY(-2px);
      background: rgba(213, 178, 100, 0.13);
    }

    /* both exits go dim while the reels turn */

    .rw-done:disabled,
    .rw-close:disabled {
      opacity: 0.35;
      cursor: not-allowed;
    }

    .rw-done:disabled {
      color: var(--text-muted);
      border-color: var(--border);
    }

    /* and light up the moment the number lands */

    @keyframes done-ready {
      0%, 100% { box-shadow: 0 0 0 rgba(213, 178, 100, 0); }
      50% { box-shadow: 0 0 26px rgba(213, 178, 100, 0.45); }
    }

    .rw-done.is-ready {
      animation: done-ready 1.5s ease-in-out 3;
    }

    /* ==========================================================
       SPELL RESULT MODAL
    ========================================================== */


    .sp-prize {
      position: relative;
      z-index: 2;

      margin-top: 20px;
      padding: 20px 18px;

      background: rgba(255,255,255,0.03);
      border: 1px dashed rgba(213, 178, 100, 0.4);
      border-radius: 16px;
    }

    .sp-prize-label {
      color: var(--text-muted);
      font-size: 10px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 2px;
    }

    .sp-code {
      margin-top: 10px;

      font-family: "Cinzel", serif;
      font-size: clamp(22px, 6vw, 30px);
      font-weight: 700;
      letter-spacing: 2px;

      color: var(--gold-light);

      word-break: break-all;
    }

    .sp-terms {
      margin-top: 10px;
      color: var(--text-soft);
      font-size: 11.5px;
      line-height: 1.5;
    }



    /* ==========================================================
       THE CAST EFFECT

       Particles are spawned into .fx-layer by playCastFx().
       Every animation reads --fx-dur (set per tier) so a tier 0
       flicker and a tier 5 eruption share the same code.
    ========================================================== */

    .fx-layer {
      position: absolute;
      inset: 0;
      z-index: 6;

      overflow: hidden;
      border-radius: inherit;

      pointer-events: none;
    }

    .fx-p {
      position: absolute;
      will-change: transform, opacity;
    }

    /* the card itself reacts */

    @keyframes fx-card {
      0%, 100% { box-shadow: 0 35px 90px rgba(0,0,0,0.6); }
      35% {
        box-shadow:
          0 0 calc(70px * var(--fx-power, 0.5)) var(--pip),
          0 0 calc(180px * var(--fx-power, 0.5)) var(--pip-glow),
          0 35px 90px rgba(0,0,0,0.6);
      }
    }

    .rw-card.is-casting {
      animation: fx-card var(--fx-dur, 1200ms) ease-out;
    }

    /* central bloom, on every colour */

    .fx-bloom {
      position: absolute;
      left: 50%;
      top: 46%;

      width: 40px;
      height: 40px;
      margin: -20px 0 0 -20px;

      border-radius: 50%;

      background: radial-gradient(circle, var(--pip), transparent 70%);

      animation: fx-bloom var(--fx-dur, 1200ms) ease-out forwards;
    }

    @keyframes fx-bloom {
      0% { transform: scale(0.2); opacity: 0; }
      22% { opacity: calc(0.75 * var(--fx-power, 0.5)); }
      100% { transform: scale(24); opacity: 0; }
    }

    /* WHITE — rays of light */

    .fx-ray {
      left: 50%;
      top: 46%;

      width: 46px;
      height: 2px;

      transform-origin: 0 50%;

      background: linear-gradient(90deg, transparent, var(--mana-white));

      animation: fx-radial var(--fx-dur, 1200ms) cubic-bezier(.15,.75,.3,1) forwards;
    }

    /* COLORLESS — thrown shards */

    .fx-shard {
      left: 50%;
      top: 46%;

      width: 16px;
      height: 3px;

      transform-origin: 0 50%;

      border-radius: 2px;
      background: var(--mana-colorless);

      animation: fx-radial var(--fx-dur, 1200ms) cubic-bezier(.1,.8,.3,1) forwards;
    }

    @keyframes fx-radial {
      0% {
        transform: rotate(var(--fx-angle, 0deg)) translateX(0) scaleX(0.2);
        opacity: 0;
      }
      18% { opacity: 1; }
      100% {
        transform: rotate(var(--fx-angle, 0deg)) translateX(var(--fx-travel, 120px)) scaleX(1);
        opacity: 0;
      }
    }

    /* BLUE — ripples and rain */

    .fx-ring {
      left: 50%;
      top: 46%;

      width: 60px;
      height: 60px;
      margin: -30px 0 0 -30px;

      border-radius: 50%;
      border: 2px solid var(--pip);

      animation: fx-ring var(--fx-dur, 1200ms) cubic-bezier(.2,.7,.3,1) forwards;
    }

    @keyframes fx-ring {
      0% { transform: scale(0.2); opacity: 0.9; }
      100% { transform: scale(8); opacity: 0; }
    }

    .fx-drop {
      top: 0;

      width: 4px;
      height: 11px;

      border-radius: 0 0 4px 4px;
      background: linear-gradient(var(--mana-blue), transparent);

      animation: fx-fall var(--fx-dur, 1200ms) cubic-bezier(.4,.1,.7,1) forwards;
    }

    @keyframes fx-fall {
      0% { transform: translateY(-20px) scaleY(0.5); opacity: 0; }
      20% { opacity: 1; }
      100% { transform: translateY(var(--fx-travel, 150px)) scaleY(1.3); opacity: 0; }
    }

    /* RED — embers.  BLACK — motes.  GREEN — leaves. */

    .fx-ember,
    .fx-mote,
    .fx-leaf {
      bottom: 12%;
      animation: fx-rise var(--fx-dur, 1200ms) cubic-bezier(.3,.5,.4,1) forwards;
    }

    .fx-ember {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: radial-gradient(circle, #ffd9a0, var(--mana-red) 60%, transparent);
      box-shadow: 0 0 10px var(--mana-red);
    }

    .fx-mote {
      width: 5px;
      height: 5px;
      border-radius: 50%;
      background: var(--mana-black);
      box-shadow: 0 0 12px var(--mana-black);
      filter: blur(0.4px);
    }

    .fx-leaf {
      width: 11px;
      height: 6px;
      border-radius: 50% 0 50% 0;
      background: var(--mana-green);
      box-shadow: 0 0 9px rgba(79, 194, 129, 0.5);
    }

    @keyframes fx-rise {
      0% {
        transform: translateY(0) rotate(0deg) scale(0.5);
        opacity: 0;
      }
      15% { opacity: 1; }
      100% {
        transform:
          translateY(calc(-1 * var(--fx-travel, 150px)))
          rotate(var(--fx-spin, 90deg))
          scale(1.1);
        opacity: 0;
      }
    }

    /* ==========================================================
       SPELL MODAL DETAIL
    ========================================================== */





    .sp-prize.is-arriving {
      animation: sp-prize-in 0.7s cubic-bezier(.2,.9,.3,1.2) both;
    }

    @keyframes sp-prize-in {
      from { transform: scale(0.86); opacity: 0; }
      to { transform: scale(1); opacity: 1; }
    }

    .log-heading {
      margin-bottom: 10px;

      color: var(--text-muted);

      font-size: 10px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 2px;
    }

    /* ==========================================================
       SPELL MODAL DETAIL
    ========================================================== */

    /* one line under the flavour saying what the spell gives */

    .sp-reward-note {
      margin-top: 12px;

      color: var(--gold-light);

      font-size: 12px;
      font-weight: 700;
      line-height: 1.5;
    }

    .sp-reward-note.is-unwritten {
      color: var(--text-muted);
      font-weight: 400;
      font-style: italic;
    }

    /* THE CAST BUTTON

       Deliberately the same gold as the Cast button in the
       spellbook, so it reads as the same action rather than a
       new one. It carries the cost as orbs — the only place the
       cost appears in the modal, so nothing is said twice. */

    .sp-prize.is-arriving {
      animation: sp-prize-in 0.7s cubic-bezier(.2,.9,.3,1.2) both;
    }

    @keyframes sp-prize-in {
      from { transform: scale(0.86); opacity: 0; }
      to { transform: scale(1); opacity: 1; }
    }

    /* ==========================================================
       CAST HISTORY  (sits below the call to action)
    ========================================================== */

    .log-list {
      position: relative;
      z-index: 2;

      margin-top: 22px;

      text-align: left;
    }

    .log-heading {
      margin-bottom: 9px;

      color: var(--text-muted);

      font-size: 10px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 2px;
    }

    .log-entry {
      display: flex;
      align-items: center;
      gap: 13px;

      padding: 12px 14px;

      background: rgba(255, 255, 255, 0.03);

      border: 1px solid var(--border);
      border-radius: 13px;
    }

    .log-entry + .log-entry {
      margin-top: 8px;
    }

    .log-index {
      flex: 0 0 auto;

      width: 27px;
      height: 27px;

      display: grid;
      place-items: center;

      border-radius: 50%;

      background: rgba(255, 255, 255, 0.05);
      border: 1px solid var(--pip);

      color: var(--pip);

      font-size: 11px;
      font-weight: 800;
    }

    .log-main {
      flex: 1;
      min-width: 0;
    }

    .log-prize {
      font-family: "Cinzel", serif;
      font-size: 14px;
      font-weight: 600;

      color: var(--gold-light);

      word-break: break-all;
    }

    .log-meta {
      margin-top: 3px;

      color: var(--text-muted);

      font-size: 10.5px;
      letter-spacing: 0.3px;
    }

    .log-empty {
      margin-top: 18px;

      color: var(--text-muted);

      font-size: 11.5px;
      text-align: center;
    }

    /* ==========================================================
       STORE LINKS

       Five touchpoints, four of them quiet. The rule is that a
       link only appears where the player already wants the
       thing it offers: they are short of mana, or they have
       just been paid, or they have reached the end of the page.
       None of them interrupt a task.
    ========================================================== */

    .store-logo-link {
      flex: 0 0 auto;
      display: block;
      border-radius: 20px;

      transition: transform 0.25s ease;
    }

    .store-logo-link:hover {
      transform: translateY(-3px) scale(1.02);
    }

    .nudge-link {
      flex: 0 0 auto;
      margin-left: auto;

      color: var(--gold-light);

      font-size: 11px;
      font-weight: 800;
      text-decoration: none;
      white-space: nowrap;

      border-bottom: 1px solid rgba(213, 178, 100, 0.4);

      transition: border-color 0.2s ease;
    }

    .nudge-link:hover {
      border-bottom-color: var(--gold-light);
    }

    /* the one prominent placement */

    .store-band {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 20px;

      margin-top: 34px;
      padding: 18px 22px;

      text-decoration: none;
      color: inherit;

      background:
        linear-gradient(120deg, rgba(213, 178, 100, 0.10), rgba(213, 178, 100, 0.02));

      border: 1px solid rgba(213, 178, 100, 0.28);
      border-radius: var(--radius-medium);

      transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
    }

    .store-band:hover {
      transform: translateY(-2px);
      border-color: rgba(213, 178, 100, 0.55);
      box-shadow: 0 14px 36px rgba(0, 0, 0, 0.3);
    }

    .store-band-title {
      font-family: "Cinzel", serif;
      font-size: 18px;
      font-weight: 600;

      color: var(--gold-light);
    }

    .store-band-line {
      margin-top: 4px;

      color: var(--text-soft);

      font-size: 12px;
      line-height: 1.5;
    }

    .store-band-go {
      flex: 0 0 auto;

      padding: 11px 18px;

      color: #120d02;
      background: linear-gradient(145deg, var(--gold-light), var(--gold));

      border-radius: 10px;

      font-size: 11px;
      font-weight: 800;
      text-transform: uppercase;
      letter-spacing: 1.3px;
      white-space: nowrap;
    }

    /* in the spell modal, only when they cannot pay */

    .sp-store {
      position: relative;
      z-index: 2;

      display: block;
      margin-top: 12px;

      color: var(--gold);

      font-size: 11.5px;
      font-weight: 700;
      text-decoration: none;
    }

    .sp-store:hover {
      color: var(--gold-light);
      text-decoration: underline;
    }

    .sp-store[hidden] { display: none; }

    /* in the redemption modal, after the payout lands */

    .rw-store-link {
      display: inline-block;
      margin-top: 10px;

      color: var(--text-muted);

      font-size: 11px;
      text-decoration: none;

      border-bottom: 1px solid rgba(255, 255, 255, 0.14);

      opacity: 0;
      transition: opacity 0.5s ease 0.3s, color 0.2s ease;
    }

    .rw-store-link:hover {
      color: var(--gold-light);
    }

    .rw-result.is-landed .rw-store-link {
      opacity: 1;
    }

    /* ==========================================================
       MOBILE
    ========================================================== */

    @media (max-width: 700px) {

      :root { --reel-digit: 52px; }

      .app {
        width: min(100% - 22px, 1180px);
        padding-top: 15px;
      }

      .player-card { padding: 20px 14px; }

      .player-top {
        flex-direction: column-reverse;
        align-items: flex-start;
        gap: 14px;
      }

      .store-logo {
        width: 72px;
        height: 72px;
      }

      .player-description {
        margin-top: 10px;
        font-size: 12.5px;
        line-height: 1.5;
      }

      .player-title { margin-top: 8px; }

      /* the pool stays on ONE line at every width — the tiles
         shrink instead of wrapping to a second row */

      .pool { margin-top: 16px; }

      .pool-note { font-size: 9.5px; }

      .pool-grid { gap: 4px; }

      .mana-tile { padding: 9px 2px; border-radius: 11px; }

      .mana-pip { width: 14px; height: 14px; margin-bottom: 5px; }

      .mana-balance { font-size: 13px; }

      .mana-name {
        margin-top: 4px;
        font-size: 6.5px;
        letter-spacing: 0.3px;
      }

      .mana-lifetime { font-size: 7px; margin-top: 2px; }

      /* stats stay three across too */

      .stat { padding: 9px 7px; }

      .stat-value { font-size: 15px; }

      .stat-label {
        font-size: 7px;
        letter-spacing: 0.5px;
      }

      .nudge {
        flex-wrap: wrap;
        padding: 9px 12px;
      }

      .nudge-text { font-size: 11.5px; }

      .nudge-link { font-size: 10.5px; }

      .store-band {
        flex-direction: column;
        align-items: flex-start;
        gap: 14px;
        padding: 16px;
        margin-top: 26px;
      }

      .store-band-title { font-size: 16px; }

      .store-band-line { font-size: 11.5px; }

      .store-band-go {
        width: 100%;
        text-align: center;
      }

      /* one scrollable line of tabs rather than two stacked rows */
      .spell-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        padding-bottom: 2px;
        margin-bottom: 12px;
      }

      .spell-tabs::-webkit-scrollbar { display: none; }

      .spell-tab {
        flex: 0 0 auto;
        padding: 8px 13px;
        font-size: 10px;
      }

      .section { margin-top: 26px; }

      .section-description { font-size: 11.5px; }

      .section-heading {
        align-items: flex-start;
        flex-direction: column;
        gap: 7px;
      }

      .section-description {
        text-align: left;
        max-width: none;
      }

      .tribe-chips {
        grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
        gap: 7px;
      }

      .tribe-chip { padding: 10px 6px 9px; }

      .tribe-face { width: 46px; height: 46px; }

      .tribe-glyph { font-size: 22px; }

      .tribe-label { font-size: 11px; }

      .collection-summary { padding: 10px 13px; }

      .collection-line { font-size: 12px; }

      /* one spell per row on a phone — minmax(0, …) again, or
         the nowrap flavour pushes the button off-screen */
      .spellbook { grid-template-columns: minmax(0, 1fr); }

      .spell { padding: 11px 12px 11px 14px; gap: 10px; }

      .spell-name { font-size: 14.5px; }



      /* the flavour and the shortfall each drop to their own
         line rather than being cut off mid-word */
      .spell-main { white-space: normal; }

      .spell-name,
      .spell-flavour,
      .spell-short {
        display: block;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }

      .spell-flavour {
        margin-top: 2px;
        font-size: 10.5px;
      }

      .spell-short {
        margin-top: 2px;
        font-size: 10.5px;
      }

      .spell-flavour .dash,
      .spell-short .dash { display: none; }

      .sp-cast { padding: 8px 11px; font-size: 10.5px; gap: 7px; }

      .sp-cast .cost { font-size: 12px; }

      .rw-overlay { padding: 10px; }

      .rw-card {
        max-height: calc(100dvh - 20px);
        padding: 26px 18px 20px;
      }

      .rw-sub { font-size: 12.5px; }
      .rw-receipt-row { padding: 9px 0; }
      .rw-receipt-row dd { font-size: 12.5px; }
      .rw-cta { padding: 14px 22px; font-size: 12.5px; }
      .rw-reel-col { width: 40px; }
      .rw-mana-label { font-size: 19px; }
    }

    @media (max-height: 720px) {

      :root { --reel-digit: 46px; }

      .rw-card { padding: 22px 18px 18px; }
      .rw-title { font-size: clamp(21px, 5vw, 26px); }
      .rw-sub { margin-top: 8px; font-size: 12px; }
      .rw-receipt-row { padding: 8px 0; }
      .rw-reel-col { width: 36px; }
      .rw-mana-label { margin-top: 10px; font-size: 18px; }
      .rw-done { padding: 11px 18px; }
      .sp-prize { margin-top: 14px; padding: 15px; }
    }

    @media (max-height: 600px) {

      :root { --reel-digit: 40px; }

      .rw-sub { display: none; }
      .rw-receipt-row.rw-secondary { display: none; }
      .rw-close { top: 8px; right: 8px; }
      .rw-card { padding: 18px 16px 16px; }
      .rw-xp-note { display: none; }
    }

    @media (max-height: 480px) {

      :root { --reel-digit: 34px; }

      .rw-card { padding: 13px 16px 12px; }
      .rw-title { margin-top: 6px; font-size: 18px; }
      .rw-eyebrow { font-size: 9px; }
      .rw-flip { height: 104px; }
      .rw-mark { font-size: 52px; }
      .rw-receipt { margin-top: 10px; }
      .rw-receipt-row { padding: 7px 0; }
      .rw-reveal-zone { min-height: 66px; margin-top: 10px; }
      .rw-stage { margin-top: 10px; }
      .rw-cta { padding: 11px 18px; font-size: 12px; }
      .rw-reel-col { width: 28px; }
      .rw-mana-label { margin-top: 8px; font-size: 16px; }
      .rw-done { margin-top: 12px; padding: 10px 16px; font-size: 10px; }
    }

    @media (prefers-reduced-motion: reduce) {
      .progress-fill::after,
      .rw-face-front::after,
      .rw-cta::after,
      .rw-flip,
      .rw-cta,

      .rw-flip-inner { transition: none; }
    }

