/*
 * Design tokens for light/dark (spec §56). Both palettes are intentionally
 * designed, not a simple inversion. Rarity colors (spec §57) live here too
 * since they're used across Dashboard/Inventory/Profile.
 */

:root {
    --bg: #f5f3fb;
    --bg-elevated: #ffffff;
    --bg-sunken: #ece9f7;
    --surface-border: #e1ddf0;
    --text-primary: #201b34;
    --text-secondary: #635c7d;
    --text-muted: #948dab;
    --accent: #7c4dff;
    --accent-strong: #5e2fe0;
    --accent-soft: #efe8ff;
    --success: #1fae6b;
    --danger: #e5484d;
    --warning: #c98a1a;
    --shadow-color: 240deg 30% 60%;

    --rarity-basic: #9aa0ac;
    --rarity-good: #4caf7d;
    --rarity-rare: #3d8bff;
    --rarity-epic: #a45bff;
    --rarity-legendary: #ff9f2e;
    --rarity-mythic: #ff5da2;
    --rarity-celestial: #35d0d0;
    --rarity-exclusive: #ffd54a;

    --font-body: 'Segoe UI', system-ui, -apple-system, sans-serif;
    --radius-sm: 8px;
    --radius-md: 14px;
    --radius-lg: 20px;
}

:root[data-theme="dark"] {
    --bg: #14111f;
    --bg-elevated: #1d1930;
    --bg-sunken: #0e0c18;
    --surface-border: #322a4d;
    --text-primary: #f1eefb;
    --text-secondary: #b6aed1;
    --text-muted: #7c7396;
    --accent: #9c7bff;
    --accent-strong: #b294ff;
    --accent-soft: #2a2246;
    --success: #33d689;
    --danger: #ff6b70;
    --warning: #ffb648;
    --shadow-color: 260deg 60% 4%;
}

* { box-sizing: border-box; }

html, body {
    height: 100%;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text-primary);
    font-family: var(--font-body);
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }

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

.surface {
    background: var(--bg-elevated);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-md);
}

.btn-accent {
    background: linear-gradient(135deg, var(--accent), var(--accent-strong));
    color: #fff;
    border: none;
    border-radius: var(--radius-sm);
    padding: .55rem 1.1rem;
    font-weight: 600;
    transition: transform .12s ease, box-shadow .12s ease;
}
.btn-accent:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 8px 20px hsl(var(--shadow-color) / .35);
    color: #fff;
}
.btn-accent:disabled { opacity: .55; cursor: not-allowed; transform: none; }

.btn-ghost {
    background: var(--bg-sunken);
    color: var(--text-primary);
    border: 1px solid var(--surface-border);
    border-radius: var(--radius-sm);
    padding: .5rem 1rem;
}
.btn-ghost:hover { background: var(--accent-soft); color: var(--text-primary); }

.rarity-badge {
    display: inline-flex;
    /* .card-face is a column flexbox with default align-items:stretch, so
       without this the badge stretches to the card's full width instead of
       hugging its own text like a real badge. */
    align-self: flex-start;
    align-items: center;
    gap: .3rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: .15rem .55rem;
    border-radius: 999px;
    color: #14111f;
    /* Semi-transparent so the card art underneath still reads through the
       badge instead of the badge sitting as an opaque block on top of it. */
    opacity: .8;
}
.rarity-basic { background: var(--rarity-basic); }
.rarity-good { background: var(--rarity-good); color: #fff; }
.rarity-rare { background: var(--rarity-rare); color: #fff; }
.rarity-epic { background: var(--rarity-epic); color: #fff; }
.rarity-legendary { background: var(--rarity-legendary); color: #201b34; }
.rarity-mythic { background: var(--rarity-mythic); color: #fff; }
.rarity-celestial { background: var(--rarity-celestial); color: #06282a; }
.rarity-exclusive { background: var(--rarity-exclusive); color: #1a0033; }

/* VIP badge/title — gold and distinct from the individually colored team roles. */
.badge-vip {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .03em;
    padding: .1rem .45rem;
    border-radius: 999px;
    background: linear-gradient(135deg, #f2c94c, #d4a017);
    color: #221600;
}

.badge-role {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    border: 1px solid transparent;
    font-weight: 700;
    line-height: 1;
    vertical-align: middle;
}

.badge-role-owner {
    border-color: #f7c948;
    background: linear-gradient(135deg, #f6ad1b, #c87500);
    color: #241300;
}

.badge-role-admin {
    border-color: #7cb8ff;
    background: linear-gradient(135deg, #2878df, #164caa);
    color: #fff;
}

.badge-role-staff {
    border-color: #65d6c1;
    background: linear-gradient(135deg, #159b8a, #0b655d);
    color: #fff;
}

.card-face {
    aspect-ratio: 3 / 4;
    border-radius: var(--radius-md);
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: .6rem;
    color: #fff;
    font-weight: 600;
    border: 2px solid transparent;
    /* Subtle outline so name/CPS text stays legible when the card's photo art
       (set via cardArtStyle()'s background-image) is light/white in that spot. */
    text-shadow: 0 1px 3px rgba(0, 0, 0, .65), 0 0 1px rgba(0, 0, 0, .5);
}
.card-lock-badge {
    position: absolute;
    top: .5rem;
    right: .5rem;
    width: 1.6rem;
    height: 1.6rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    font-size: .8rem;
    text-shadow: none;
}
.card-face.rarity-basic { background: linear-gradient(160deg, #7d828e, #4d515c); border-color: var(--rarity-basic); }
.card-face.rarity-good { background: linear-gradient(160deg, #57c78f, #2c7a55); border-color: var(--rarity-good); }
.card-face.rarity-rare { background: linear-gradient(160deg, #5aa1ff, #23509e); border-color: var(--rarity-rare); }
.card-face.rarity-epic { background: linear-gradient(160deg, #bb7dff, #6421b8); border-color: var(--rarity-epic); box-shadow: 0 0 18px -4px var(--rarity-epic); }
.card-face.rarity-legendary { background: linear-gradient(160deg, #ffc262, #d97800); border-color: var(--rarity-legendary); box-shadow: 0 0 20px -2px var(--rarity-legendary); }
.card-face.rarity-mythic { background: linear-gradient(160deg, #ff8dc4, #c22a72); border-color: var(--rarity-mythic); box-shadow: 0 0 22px -2px var(--rarity-mythic); }
.card-face.rarity-celestial { background: linear-gradient(160deg, #7cf0f0, #0d8f8f); border-color: var(--rarity-celestial); box-shadow: 0 0 26px -2px var(--rarity-celestial); }
.card-face.rarity-exclusive { background: linear-gradient(160deg, var(--rarity-exclusive), #a67d00); border-color: var(--rarity-exclusive); box-shadow: 0 0 26px -2px var(--rarity-exclusive); }

@media (prefers-reduced-motion: no-preference) {
    .card-face { transition: transform .15s ease; }
    .card-face:hover { transform: translateY(-4px); }
}

/* Batch 7 item 7 — mutation glow (services/cardArt.js's mutationCardFaceClass()).
   `filter: drop-shadow()` is a different rendering stage from the rarity
   rules' own `box-shadow` above, so the two glows layer instead of one
   overriding the other — the rarity border/background/box-shadow above is
   never touched. Normal cards get no extra class and therefore no glow at
   all. The static (non-animated) filter values below are always applied so
   the mutation stays visually identifiable even under reduced motion; the
   animation only adds movement on top of that already-visible glow. */
.card-face.mutation-shiny {
    filter: drop-shadow(0 0 6px rgba(255, 255, 255, .8)) drop-shadow(0 0 14px rgba(190, 225, 255, .65));
}
.card-face.mutation-prismatic {
    filter: drop-shadow(0 0 8px rgba(255, 255, 255, .9)) drop-shadow(0 0 18px rgba(255, 130, 220, .7)) drop-shadow(0 0 28px rgba(130, 200, 255, .55));
}
/* Batch 23: :root:not([data-low-spec]) extends this same reduced-motion
   gate to also respect the account-scoped Low Spec Mode toggle (a
   deliberate player choice, composing with rather than replacing the
   OS-level media query) — one shared gate per effect, not a second
   parallel one (services/lowSpec.js sets the attribute). */
@media (prefers-reduced-motion: no-preference) {
    :root:not([data-low-spec]) .card-face.mutation-shiny { animation: mutation-shiny-pulse 2.2s ease-in-out infinite; }
    /* Prismatic cycles through hue as well as pulsing — visibly rarer/more
       eventful than Shiny's single-color pulse, per the item 7 spec. */
    :root:not([data-low-spec]) .card-face.mutation-prismatic { animation: mutation-prismatic-shift 3.6s ease-in-out infinite; }
}
@keyframes mutation-shiny-pulse {
    0%, 100% { filter: drop-shadow(0 0 6px rgba(255, 255, 255, .7)) drop-shadow(0 0 12px rgba(190, 225, 255, .5)); }
    50% { filter: drop-shadow(0 0 10px rgba(255, 255, 255, 1)) drop-shadow(0 0 20px rgba(190, 225, 255, .85)); }
}
@keyframes mutation-prismatic-shift {
    0%, 100% { filter: drop-shadow(0 0 8px rgba(255, 255, 255, .9)) drop-shadow(0 0 18px rgba(255, 130, 220, .7)) drop-shadow(0 0 28px rgba(130, 200, 255, .55)); }
    33% { filter: drop-shadow(0 0 8px rgba(255, 255, 255, .9)) drop-shadow(0 0 18px rgba(255, 225, 130, .7)) drop-shadow(0 0 28px rgba(180, 130, 255, .55)); }
    66% { filter: drop-shadow(0 0 8px rgba(255, 255, 255, .9)) drop-shadow(0 0 18px rgba(130, 255, 200, .7)) drop-shadow(0 0 28px rgba(255, 130, 220, .55)); }
}

/* Production follow-up: a sheen sweep (::after) and a small twinkle-sparkle
   cluster (::before), on top of the glow above. Both are pure CSS — no extra
   DOM particles, no animation library — so a grid of dozens of mutated cards
   stays cheap: every animated property here is `opacity`/`transform`, which
   the browser can composite on the GPU without re-triggering layout, unlike
   animating `left`/`top`/`background-position` would. Every direct child of
   a mutated .card-face (the rarity badge, mutation badge, name/CPS text —
   whatever each view puts inside) gets its own stacking context above these
   layers, so the effect can never visually cover the card's real content,
   regardless of which view rendered it. `pointer-events: none` keeps them
   from ever intercepting a click meant for the card underneath. Both
   pseudo-elements default to invisible (opacity: 0) and only the
   no-preference media query below ever animates them to visible — so
   reduced-motion users see just the static glow/badge from above, never a
   frozen mid-effect artifact. */
.card-face.mutation-shiny > *:not(.card-lock-badge),
.card-face.mutation-prismatic > *:not(.card-lock-badge) {
    position: relative;
    z-index: 2;
}
/* .card-lock-badge already positions itself (top-right corner) — only lift
   its stacking order here, without touching that positioning. The Inventory
   select-mode checkbox similarly sets `position: absolute` inline (which
   always wins over the rule above regardless), so it only needs the same
   z-index boost, which the rule above already gives it. */
.card-face.mutation-shiny > .card-lock-badge,
.card-face.mutation-prismatic > .card-lock-badge {
    z-index: 2;
}
.card-face.mutation-shiny::before,
.card-face.mutation-shiny::after,
.card-face.mutation-prismatic::before,
.card-face.mutation-prismatic::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    pointer-events: none;
    z-index: 1;
    opacity: 0;
}
/* ::before needs full-width coverage for its twinkle dots; ::after is
   deliberately narrower than the card (see each mutation's own rule below)
   so it reads as a moving band rather than a full-card wash. */
.card-face.mutation-shiny::before,
.card-face.mutation-prismatic::before {
    left: 0;
    right: 0;
}

/* Shiny: a few small white twinkle points (::before) plus one soft diagonal
   light sheen that sweeps across and then rests (::after) — "noticeable but
   not visually noisy" per spec, so the sweep pauses for most of its cycle
   rather than sweeping continuously. */
.card-face.mutation-shiny::before {
    background:
        radial-gradient(circle, #fff 0%, transparent 65%) 18% 22% / 7px 7px no-repeat,
        radial-gradient(circle, #fff 0%, transparent 65%) 78% 18% / 5px 5px no-repeat,
        radial-gradient(circle, #fff 0%, transparent 65%) 60% 72% / 6px 6px no-repeat;
}
.card-face.mutation-shiny::after {
    width: 45%;
    left: -45%;
    background: linear-gradient(115deg, transparent 0%, rgba(255, 255, 255, .55) 45%, rgba(255, 255, 255, .8) 50%, rgba(255, 255, 255, .55) 55%, transparent 100%);
    transform: skewX(-18deg);
}
@media (prefers-reduced-motion: no-preference) {
    :root:not([data-low-spec]) .card-face.mutation-shiny::before { animation: mutation-shiny-twinkle 2.4s ease-in-out infinite; }
    :root:not([data-low-spec]) .card-face.mutation-shiny::after { animation: mutation-shiny-sweep 4s ease-in-out infinite; }
}
@keyframes mutation-shiny-twinkle {
    0%, 100% { opacity: .25; }
    50% { opacity: .85; }
}
@keyframes mutation-shiny-sweep {
    0%, 55% { transform: translateX(0%) skewX(-18deg); opacity: 0; }
    8% { opacity: .9; }
    35% { opacity: .9; }
    45% { transform: translateX(300%) skewX(-18deg); opacity: 0; }
    100% { transform: translateX(300%) skewX(-18deg); opacity: 0; }
}

/* Prismatic: more/brighter twinkle points in rainbow tints, and a wider,
   hue-shifting sheen on a shorter cycle — deliberately stronger and more
   "eventful" than Shiny, per spec ("visually more prestigious than Shiny"). */
.card-face.mutation-prismatic::before {
    background:
        radial-gradient(circle, #ff9de0 0%, transparent 65%) 15% 20% / 8px 8px no-repeat,
        radial-gradient(circle, #9de0ff 0%, transparent 65%) 78% 16% / 6px 6px no-repeat,
        radial-gradient(circle, #fff29d 0%, transparent 65%) 55% 72% / 7px 7px no-repeat,
        radial-gradient(circle, #c39dff 0%, transparent 65%) 25% 82% / 6px 6px no-repeat,
        radial-gradient(circle, #9dffc3 0%, transparent 65%) 88% 62% / 5px 5px no-repeat;
}
.card-face.mutation-prismatic::after {
    width: 50%;
    left: -50%;
    background: linear-gradient(115deg, transparent 0%, rgba(255, 210, 240, .55) 35%, rgba(255, 255, 255, .85) 48%, rgba(190, 225, 255, .6) 60%, transparent 100%);
    transform: skewX(-18deg);
}
@media (prefers-reduced-motion: no-preference) {
    :root:not([data-low-spec]) .card-face.mutation-prismatic::before { animation: mutation-prismatic-twinkle 1.8s ease-in-out infinite; }
    :root:not([data-low-spec]) .card-face.mutation-prismatic::after { animation: mutation-prismatic-sweep 3s ease-in-out infinite; }
}
@keyframes mutation-prismatic-twinkle {
    0%, 100% { opacity: .35; }
    50% { opacity: 1; }
}
@keyframes mutation-prismatic-sweep {
    0%, 45% { transform: translateX(0%) skewX(-18deg); opacity: 0; }
    6% { opacity: .95; }
    30% { opacity: .95; }
    38% { transform: translateX(280%) skewX(-18deg); opacity: 0; }
    100% { transform: translateX(280%) skewX(-18deg); opacity: 0; }
}

.mutation-badge {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: .25rem;
    font-size: .64rem;
    font-weight: 800;
    letter-spacing: .03em;
    text-transform: uppercase;
    padding: .12rem .5rem;
    border-radius: 999px;
    margin-top: .2rem;
}

/* Card badge row: rarity badge + mutation badge, grouped on one line, sitting
   above the card art as its own row instead of overlaid on top of the image
   or stacked loose inside .card-face's own flex flow. Each call site places
   this as a sibling before its .card-face element (never a child of it) —
   see cardArt.js's cardTopBadgesHtml(). Plain flow, no absolute positioning,
   so it simply takes its own line above the card. */
.card-badge-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .25rem;
    overflow: hidden;
    margin-bottom: .35rem;
}
.card-badge-row .rarity-badge,
.card-badge-row .mutation-badge {
    margin-top: 0;
    flex-shrink: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: .58rem;
    padding: .1rem .4rem;
}
/* The name/CPS caption at the bottom of a .card-face (the block wrapped in
   Bootstrap's .mt-auto to pin it there) reads as a centered 3-line group
   together with .card-badge-row above it — badge row, name, CPS — instead
   of the badge row's centered line sitting over left-aligned text. */
.card-face > .mt-auto {
    text-align: center;
}
.mutation-badge-shiny {
    background: linear-gradient(135deg, #eaf6ff, #9fd8ff);
    color: #0b3350;
}
.mutation-badge-prismatic {
    background: linear-gradient(115deg, #ffd1f0, #b6e0ff, #fff2b0, #ffd1f0);
    background-size: 300% 100%;
    color: #3a0b3a;
}
@media (prefers-reduced-motion: no-preference) {
    :root:not([data-low-spec]) .mutation-badge-prismatic { animation: mutation-badge-shift 3.6s ease-in-out infinite; }
}
@keyframes mutation-badge-shift {
    0%, 100% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
}

/* Box-opening reveal (store.js showReveal()) — a suspense beat before the
   pulled card appears, skippable by tapping it. The revealed card itself is
   just a normal .card-face with its real rarity class, so higher rarities
   automatically get their existing (admin-configured, runtime-installed)
   glow treatment above for free — no separate "make it feel special" logic
   needed per rarity here. */
.box-reveal-mystery {
    aspect-ratio: 3 / 4;
    max-width: 220px;
    margin: 0 auto;
    border-radius: var(--radius-md);
    background: linear-gradient(160deg, #2c2c3a, #17171f);
    border: 2px solid var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3rem;
    color: var(--accent);
    cursor: pointer;
}
.box-reveal-skip-hint {
    text-align: center;
    font-size: .78rem;
    color: var(--text-secondary);
    margin-top: .6rem;
    cursor: pointer;
}
@media (prefers-reduced-motion: no-preference) {
    .box-reveal-mystery { animation: box-reveal-pulse 1s ease-in-out infinite; }
    .box-reveal-mystery i { display: inline-block; animation: box-reveal-spin 1.8s linear infinite; }
    .box-reveal-card-in { animation: box-reveal-flip .45s ease forwards; }
}
@keyframes box-reveal-pulse {
    0%, 100% { box-shadow: 0 0 18px -4px var(--accent); }
    50% { box-shadow: 0 0 34px 2px var(--accent); }
}
@keyframes box-reveal-spin {
    from { transform: rotateY(0deg); }
    to { transform: rotateY(360deg); }
}
@keyframes box-reveal-flip {
    from { transform: rotateY(90deg); opacity: 0; }
    to { transform: rotateY(0deg); opacity: 1; }
}
