/* Self-hosted Aclonica (brand wordmark) — replaces the Google Fonts CDN so the wordmark renders
   offline and the CSP stays same-origin. woff2 subsets (latin + latin-ext) mirror Google Fonts v25
   (see vendor/fonts/). `display: swap` keeps text visible while the face loads. */
@font-face {
    font-family: 'Aclonica';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/vendor/fonts/aclonica-latin.woff2') format('woff2');
    unicode-range:
        U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
        U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Aclonica';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/vendor/fonts/aclonica-latin-ext.woff2') format('woff2');
    unicode-range:
        U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
        U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
        U+2C60-2C7F, U+A720-A7FF;
}

/* The Font Awesome sheet loads without blocking paint (index.html), so for a moment every <i>
   is an empty inline element. Reserve the box FA itself will give it (inline-block, 1em tall,
   line-height 1) so the landing header and the hero CTAs do not grow when the glyphs arrive -
   that growth was 0.096 CLS on mobile (Lighthouse 2026-09-14). min-width rather than width:
   glyphs wider than 1em keep their natural width once the sheet is in. */
.fas,
.far,
.fab {
    display: inline-block;
    min-width: 1em;
    height: 1em;
    line-height: 1;
    text-align: center;
}

/* CSS Variables for Theming */
:root {
    /* Space reserved at the bottom of a signed-out page for the fixed .app-footer; see the
       "App Footer" section. Signed-in views use body.has-app-nav's larger 64/76px instead. */
    --footer-clear: 56px; /* measured: the footer is 46px tall, plus breathing room */

    /* --- Scale tokens (NFR-G-3, G-5) ------------------------------------------------------
       Steps chosen to match the vocabulary already in the stylesheet rather than to impose a
       new one, so migrating a component is a rename and not a redesign. Not every literal maps
       (a button's 0.875rem vertical padding has no step and keeps its literal); the rule is
       that a TOUCHED component uses tokens for font size and radius, and for spacing wherever
       the value already lands on a step. */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-12: 3rem;

    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;
    --radius-pill: 999px;
    /* Legacy alias. 25 rules already said `var(--border-radius)` against a token that was
       never defined, so all 25 rendered square. Defining it is the fix; new code should reach
       for the --radius-* step it actually means. */
    --border-radius: var(--radius-md);

    --font-size-2xs: 0.7rem;
    --font-size-xs: 0.8rem;
    --font-size-sm: 0.9rem;
    --font-size-md: 1rem;
    --font-size-lg: 1.125rem;
    --font-size-xl: 1.25rem;
    --font-size-2xl: 1.5rem;
    --font-size-3xl: 2rem;

    /* Line length for prose. Long measures are the readability failure G-3 names; anything
       running as continuous text (legal, help, the accessibility statement) caps here. */
    --measure: 68ch;

    /* Light Theme (default) */
    --bg-primary: #f8f9fa;
    /* Not pure white (NFR-G-2): a faint cool tint takes the glare off large surfaces while
       keeping enough separation from the --bg-primary page (#f8f9fa) for a card to read as a
       card. */
    --bg-secondary: #fdfdfe;
    --bg-tertiary: #e9ecef;
    --text-primary: #212529;
    /* Darkened from #6c757d so secondary text clears WCAG AA 4.5:1 on the off-white page
       background and the tinted hero gradient, not just on pure white. */
    --text-secondary: #595f66;
    /* Darkened from #adb5bd (only 1.96:1 on the off-white page bg — a WCAG AA fail flagged by
       the a11y sweep across the footer, empty-state hints, scan dividers, kpi feet, etc.).
       #6c757d (gray-600) still measured 4.44 on #f8f9fa; #646b72 clears 4.5:1 (~5.1:1) with a
       margin while staying lighter than --text-secondary for hierarchy. */
    --text-muted: #646b72;
    --border-color: #dee2e6;
    /* Darkened from #0277bd: accent-primary text on a grey/tint bg (active analytics tab) was
       4.04:1 and white-on-accent hovered ~4.45:1 — under WCAG AA. #0369a1 clears both (~5.0:1
       and ~6.0:1). Light theme only; dark theme keeps its lighter --accent-primary (#29b6f6). */
    --accent-primary: #0369a1;
    --accent-primary-hover: #01579b;
    /* Background of SOLID accent buttons (white text on it). Split from --accent-primary because
       the dark theme's accent (#29b6f6) is tuned to be readable AS TEXT on a dark surface — and
       white on it is 2.3:1, an AA fail Lighthouse flagged on every primary CTA in dark mode.
       Light theme: same as the accent. Dark theme: a deeper blue that keeps white at ≥ 4.5:1. */
    --accent-fill: var(--accent-primary);
    --accent-fill-hover: var(--accent-primary-hover);
    --accent-secondary: #8b5cf6;
    --error-color: #ef4444;
    --success-color: #22c55e;
    /* Named at last: the amber "restricted" and the deep red "banned" were literals repeated
       across the legality chips (#b07900 x4) and `var(--danger-color, #c0392b)` — a token that
       was never defined, so every use silently took the fallback and dark theme never got its
       own value. Both are chosen for contrast on the light surface: #b07900 is 4.6:1 and
       #c0392b 5.1:1 on #fdfdfe, where --error-color's #ef4444 would be 3.8:1 — under AA for
       the small bold text these mark. */
    --warning-color: #b07900;
    --danger-color: #c0392b;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
    /* Was USED four times (modals, the desktop nav pill, a hovered card stack) and DEFINED
       nowhere, so every one of them rendered with no shadow at all — an invalid var() with no
       fallback drops the declaration. */
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.12), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
    --transition-speed: 0.3s;
    /* What our hover/active states actually change: paint and composite only, never layout.
       Replaces `transition: all`, which also animates width/height/padding and makes every
       row in a long list a potential reflow on hover (NFR-G-4). */
    --transition-interactive:
        border-color var(--transition-speed), background-color var(--transition-speed),
        box-shadow var(--transition-speed), color var(--transition-speed),
        transform var(--transition-speed), opacity var(--transition-speed);
}

[data-theme='dark'] {
    --bg-primary: #0f172a;
    --bg-secondary: #1e293b;
    --bg-tertiary: #334155;
    --text-primary: #f1f5f9;
    --text-secondary: #94a3b8;
    --text-muted: #64748b;
    --border-color: #475569;
    --accent-primary: #29b6f6;
    --accent-primary-hover: #0277bd;
    --accent-fill: #0277bd; /* white on it: 4.7:1 */
    --accent-fill-hover: #01579b; /* 7.2:1 */
    --accent-secondary: #a78bfa;
    --error-color: #f87171;
    --success-color: #4ade80;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
    --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.55), 0 8px 10px -6px rgba(0, 0, 0, 0.45);
    /* Lightened for the dark surface — the light-theme #b07900 / #c0392b measure 2.6:1 and
       2.9:1 on #0f172a, which is what they were rendering at before these were tokens. */
    --warning-color: #e0a92b;
    --danger-color: #f87171;
}

/* Reset & Base Styles */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    font-size: 16px;
    scrollbar-width: thin;
    scrollbar-color: var(--border-color) var(--bg-tertiary);
}

/* Custom scrollbar for Webkit browsers */
::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: var(--bg-tertiary);
}

::-webkit-scrollbar-thumb {
    background: var(--border-color);
    border-radius: 5px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--text-secondary);
}

::-webkit-scrollbar-corner {
    background: var(--bg-tertiary);
}

body {
    font-family:
        -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    line-height: 1.6;
    min-height: 100vh;
    transition:
        background-color var(--transition-speed),
        color var(--transition-speed);
}

#app {
    min-height: 100vh;
}

/* Skip-to-content link: off-screen until focused, then slides into the top-left. */
.skip-link {
    position: absolute;
    left: 0.5rem;
    top: -4rem;
    z-index: 2000;
    padding: 0.6rem 1rem;
    background-color: var(--accent-primary);
    color: #fff;
    border-radius: 0 0 8px 8px;
    text-decoration: none;
    font-weight: 600;
    transition: top var(--transition-speed);
}
.skip-link:focus {
    top: 0;
}

/* Theme Toggle Button */
.theme-toggle {
    position: fixed;
    top: 1rem;
    right: 1rem;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: 2px solid var(--border-color);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    transition: var(--transition-interactive);
    z-index: 1000;
    box-shadow: var(--shadow-md);
}

.theme-toggle:hover {
    background-color: var(--bg-tertiary);
    transform: scale(1.05);
}

.theme-toggle:active {
    transform: scale(0.95);
}

/* Show/hide sun and moon icons based on theme */
[data-theme='light'] #theme-icon-dark {
    display: none;
}

[data-theme='light'] #theme-icon-light {
    display: block;
    color: #f59e0b;
}

[data-theme='dark'] #theme-icon-light {
    display: none;
}

[data-theme='dark'] #theme-icon-dark {
    display: block;
    color: #fbbf24;
}

/* View Styles */
.view {
    min-height: 100vh;
}

/* The router toggles views via the `hidden` attribute (NFR-F-11). A per-view `display` rule
   (e.g. `#landing-view { display: flex }`) has higher specificity than the UA `[hidden]` rule
   and would otherwise leave two views stacked (e.g. the landing page over the signed-in app).
   Force hidden views off regardless of any such rule. */
.view[hidden] {
    display: none !important;
}

/* Login Container */
.login-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 2rem;
}

.login-header {
    text-align: center;
    margin-bottom: 2rem;
}

.login-header .login-brand {
    font-size: 2.5rem;
    color: var(--accent-primary);
    margin-bottom: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    user-select: none;
}

.login-header .login-brand i {
    font-size: 2rem;
}

.login-header p {
    color: var(--text-secondary);
    font-size: 1.1rem;
}

/* Login Form */
.login-form {
    width: 100%;
    max-width: 400px;
    background-color: var(--bg-secondary);
    padding: 2rem;
    border-radius: 12px;
    box-shadow: var(--shadow-lg);
    border: 1px solid var(--border-color);
}

.form-group {
    margin-bottom: var(--space-6);
}

.form-group label {
    display: block;
    margin-bottom: var(--space-2);
    font-weight: 500;
    color: var(--text-primary);
}

.input-icon-wrapper {
    position: relative;
    display: flex;
    align-items: center;
}

.input-icon {
    position: absolute;
    left: var(--space-4);
    color: var(--text-muted);
    pointer-events: none;
    z-index: 1;
}

.form-group .input-icon-wrapper input {
    padding-left: 2.75rem;
}

.input-icon-wrapper .password-toggle {
    position: absolute;
    right: var(--space-3);
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: var(--space-2);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: color var(--transition-speed);
}

.input-icon-wrapper .password-toggle:hover {
    color: var(--accent-primary);
}

.input-icon-wrapper .password-toggle.active {
    color: var(--accent-primary);
}

.input-icon-wrapper input[type='password'],
.input-icon-wrapper input:has(+ .password-toggle) {
    padding-right: 3rem;
}

.form-group input {
    width: 100%;
    padding: 0.875rem var(--space-4);
    font-size: var(--font-size-md);
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    transition:
        border-color var(--transition-speed),
        box-shadow var(--transition-speed);
}

.form-group input::placeholder {
    color: var(--text-muted);
}

.form-group input:focus,
.form-group select:focus {
    outline: none;
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 3px rgba(2, 119, 189, 0.2);
}

.form-group select {
    width: 100%;
    padding: 0.875rem 2.5rem 0.875rem var(--space-4);
    font-size: var(--font-size-md);
    border: 2px solid var(--border-color);
    border-radius: var(--radius-md);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    transition:
        border-color var(--transition-speed),
        box-shadow var(--transition-speed);
}

.form-group select:hover {
    border-color: var(--text-muted);
}

.form-group select option {
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    padding: var(--space-2);
}

/* Error Message */
.error-message {
    color: var(--error-color);
    font-size: 0.875rem;
    margin-bottom: 1rem;
    text-align: center;
    min-height: 1.25rem;
}

/* Buttons */
/* `.btn { display: inline-flex }` ties with the UA's `[hidden] { display: none }` on specificity and
   wins on order, so a hidden button stayed visible (the landing header's signed-in link). */
.btn[hidden] {
    display: none;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 0.875rem var(--space-6);
    font-size: var(--font-size-md);
    font-weight: 600;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition: var(--transition-interactive);
    user-select: none;
}

.btn-primary {
    width: 100%;
    background-color: var(--accent-fill);
    color: white;
}

.btn-primary:hover {
    background-color: var(--accent-fill-hover);
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

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

.btn-primary:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    transform: none;
}

.btn-secondary {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
    padding-left: 1.75rem;
    padding-right: 1.75rem;
    justify-content: flex-start;
}

.btn-secondary:hover {
    background-color: var(--border-color);
}

.btn-google {
    width: 100%;
    max-width: 400px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    background: #fff;
    color: #333;
    border: 1px solid var(--border-color);
}

.btn-google:hover {
    background: #f5f5f5;
}

.btn-google:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

[data-theme='dark'] .btn-google {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border-color: var(--border-color);
}

[data-theme='dark'] .btn-google:hover {
    background: var(--bg-secondary);
}

.btn-discord {
    width: 100%;
    max-width: 400px;
    margin: 0.5rem auto 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    background: #5865f2;
    color: #fff;
    border: none;
}

.btn-discord:hover {
    background: #4752c4;
}

.btn-discord:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-facebook {
    width: 100%;
    max-width: 400px;
    margin: 0.5rem auto 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    background: #1877f2;
    color: #fff;
    border: none;
}

.btn-facebook:hover {
    background: #166fe5;
}

.btn-facebook:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-github {
    width: 100%;
    max-width: 400px;
    margin: 0.5rem auto 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    background: #24292e;
    color: #fff;
    border: none;
}

.btn-github:hover {
    background: #2f363d;
}

.btn-github:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.social-login-divider {
    display: flex;
    align-items: center;
    margin: 1rem auto;
    max-width: 400px;
    width: 100%;
    color: var(--text-secondary);
}

.social-login-divider::before,
.social-login-divider::after {
    content: '';
    flex: 1;
    border-bottom: 1px solid var(--border-color);
}

.social-login-divider span {
    padding: 0 1rem;
    font-size: 0.875rem;
}

.btn-loader {
    display: none;
}

.btn.loading .btn-text {
    display: none;
}

.btn.loading .btn-loader {
    display: inline-block;
}

/* Login Footer */
.login-footer {
    margin-top: 1.5rem;
    text-align: center;
    color: var(--text-secondary);
}

.login-footer a {
    color: var(--accent-primary);
    text-decoration: none;
    font-weight: 500;
}

.login-footer a:hover {
    text-decoration: underline;
}

/* App Header */
.app-header {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 2rem;
    background-color: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
    box-shadow: var(--shadow-sm);
}

.header-brand {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--accent-primary);
    text-decoration: none;
    user-select: none;
}

.header-brand span {
    font-family: 'Aclonica', sans-serif;
}

.header-brand i {
    font-size: 1.75rem;
}

/* Header Search Form */
.header-search-form {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
    max-width: 680px;
    margin: 0 1.5rem;
}

/* The page-header instances only (.header-search-form is reused by the deck view's add-card
   form, where a shrinking input is exactly wrong - axe caught that). A flex item with basis 0%
   never shrinks below its min-content, and this form's is ~610px (the input's intrinsic width
   plus three buttons); between the 768px stack breakpoint and ~1300px the header overflowed -
   visibly in Arabic, where wider labels pushed the actions off the left edge (CI, Linux fonts).
   min-width: 0 on the form and its input lets it give way; the buttons keep their size. */
.header-search-form:not(#deck-search-form),
.header-search-form:not(#deck-search-form) .search-input-wrapper input {
    min-width: 0;
}

.header-search-form .search-input-wrapper {
    flex: 1;
    min-width: 0;
    padding: 0.25rem 0.5rem;
}

.header-search-form .search-btn {
    padding: 0.5rem 1rem;
}

/* Between the stacked-header breakpoint (768px) and ~1300px the header is tight: keep the text
   box usable by dropping the Browse/Abilities labels to their icons (each keeps its title) and
   guaranteeing the input a few characters. The primary Search button keeps its word - it has no
   icon of its own. Above this the labels come back. */
/* The deck header's action row (Paste list, Stats, Export, Edit, Lock, In collection) plus
   the add-card box measured ~1390px; at 1280px the last button was off-screen. Below 1400px
   the labels are visually hidden and the icons carry the (still translated) names. */
@media (max-width: 1400px) and (min-width: 769px) {
    #deck-view .header-actions .btn-sm > span {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
    #deck-view .header-actions .btn-sm {
        position: relative;
    }
}

@media (max-width: 1300px) and (min-width: 769px) {
    .header-search-form:not(#deck-search-form) .btn-secondary.search-btn span {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
    .header-search-form:not(#deck-search-form) .search-btn {
        padding: 0.5rem 0.75rem;
    }
    .header-search-form:not(#deck-search-form) .search-input-wrapper input {
        min-width: 8ch;
    }
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-inline-end: 40px;
}

.user-email {
    color: var(--text-secondary);
    font-size: 0.875rem;
}

/* Main Content */
.app-main {
    padding: 2rem;
    max-width: 1200px;
    margin: 0 auto;
}

.welcome-message {
    text-align: center;
    padding: 4rem 2rem;
}

.welcome-message h2 {
    font-size: 2rem;
    color: var(--text-primary);
    margin-bottom: 0.5rem;
}

.welcome-message p {
    color: var(--text-secondary);
    font-size: 1.1rem;
}

/* Responsive Design */
@media (max-width: 768px) {
    .login-header .login-brand {
        font-size: 2rem;
    }

    .login-form {
        padding: 1.5rem;
    }
    /* The fixed flag and theme buttons (top-right, 48px) sat on top of the centred brand at
       phone widths; start the page below them. */
    .login-container {
        padding-top: 5rem;
    }

    /* Stacked, but NOT sticky and NOT one-control-per-line: the stacked header measured 420px
       on a 375x812 phone and, sticky, kept more than half the screen for itself. It now
       scrolls away with the page and the action buttons share a row. */
    .app-header {
        position: static;
        flex-direction: column;
        gap: 0.75rem;
        padding: 0.75rem 1rem;
    }

    .header-actions {
        flex-wrap: wrap;
        justify-content: center;
        gap: 0.5rem;
        margin-inline-end: 0;
    }

    /* Deck title row: icon, name, two icon buttons and the format badge do not fit in 311px;
       let the badge drop to a second line rather than folding the name into a column. */
    .deck-section-header h2 {
        flex-wrap: wrap;
    }

    .theme-toggle {
        top: 0.5rem;
        right: 0.5rem;
        width: 40px;
        height: 40px;
        font-size: 1rem;
    }
}

/* Animations */
@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.view {
    animation: fadeIn 0.3s ease-out;
}

.search-input-wrapper {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background-color: var(--bg-secondary);
    border: 2px solid var(--border-color);
    border-radius: 12px;
    padding: 0.5rem 0.75rem;
    transition:
        border-color var(--transition-speed),
        box-shadow var(--transition-speed);
}

.search-input-wrapper:focus-within {
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 3px rgba(2, 119, 189, 0.2);
}

.search-icon {
    color: var(--text-muted);
    font-size: 1.25rem;
    flex-shrink: 0;
}

.search-input-wrapper input {
    flex: 1;
    border: none;
    background: transparent;
    font-size: 1.1rem;
    color: var(--text-primary);
    padding: 0.5rem;
    outline: none;
}

.search-input-wrapper input::placeholder {
    color: var(--text-muted);
}

.search-btn {
    width: auto;
    padding: 0.625rem 1.25rem;
    flex-shrink: 0;
}

.search-error {
    color: var(--error-color);
    font-size: 0.875rem;
    text-align: center;
    min-height: 1.25rem;
    padding: 0.5rem;
}

.search-error:empty {
    display: none;
}

/* Search Results */
.search-results {
    padding: 1rem 2rem 2rem;
    max-width: 1000px;
    margin: 0 auto;
}

.results-count {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin-bottom: 1rem;
    text-align: center;
}

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1.5rem;
}

.card-item {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 1.5rem;
    box-shadow: var(--shadow-md);
    transition:
        transform var(--transition-speed),
        box-shadow var(--transition-speed);
}

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

/* Card Art */
.card-art-container {
    margin-bottom: 1rem;
    text-align: center;
}

.card-art {
    max-width: 100%;
    height: auto;
    max-height: 450px;
    border-radius: 8px;
    box-shadow: var(--shadow-md);
    object-fit: contain;
}

.card-name {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--accent-primary);
    margin-bottom: 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.card-name i {
    font-size: 1rem;
}

.card-details {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.card-field {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    font-size: 0.875rem;
    line-height: 1.4;
}

.card-field-label {
    font-weight: 600;
    color: var(--text-secondary);
    min-width: 100px;
}

.card-field-value {
    color: var(--text-primary);
    word-break: break-word;
    flex: 1;
}

.language-flag {
    width: 20px;
    height: 14px;
    margin-right: 6px;
    vertical-align: middle;
    border-radius: 2px;
}

.set-icon-container {
    display: inline-block;
    width: 18px;
    height: 18px;
    margin-right: 6px;
    vertical-align: middle;
}

.set-icon {
    width: 18px;
    height: 18px;
    vertical-align: middle;
}

.card-field-value.mana-cost {
    font-family: monospace;
}

/* Per-card legality chips in the results grid */
.card-legal-chips {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 0.25rem;
}
.card-legal-chip {
    /* Was 0.65rem — the smallest type in the app and the one the axe sweep kept flagging. */
    font-size: var(--font-size-2xs);
    font-weight: 700;
    letter-spacing: 0.02em;
    padding: 0.05rem 0.35rem;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
}

/* Legality status colours, shared by the compact chips above and the pills in the deck
   legality report (`.legality-*`, further down). The two differ only in SHAPE — size, radius,
   casing — so only the shape is written twice; the colours were duplicated literal-for-literal
   in both places, which is how the two sets drifted apart in dark theme. */
.card-legal-legal,
.legality-legal {
    color: var(--success-color);
    background-color: color-mix(in srgb, var(--success-color) 14%, transparent);
    border-color: color-mix(in srgb, var(--success-color) 35%, transparent);
}
.card-legal-restricted,
.legality-restricted {
    color: var(--warning-color);
    background-color: color-mix(in srgb, var(--warning-color) 14%, transparent);
    border-color: color-mix(in srgb, var(--warning-color) 35%, transparent);
}
.legality-notlegal {
    color: var(--text-muted);
    background-color: color-mix(in srgb, var(--text-muted) 12%, transparent);
    border-color: color-mix(in srgb, var(--text-muted) 30%, transparent);
}

.card-field-value.oracle-text {
    white-space: pre-wrap;
}

.card-field-value.flavor-text {
    font-style: italic !important;
    white-space: pre-wrap;
}

/* Rules Diff Highlighting */
.diff-added {
    background-color: rgba(34, 197, 94, 0.3);
    color: #16a34a;
    padding: 0 2px;
    border-radius: 2px;
}

.diff-deleted {
    background-color: rgba(239, 68, 68, 0.3);
    color: #dc2626;
    padding: 0 2px;
    border-radius: 2px;
    text-decoration: line-through;
}

.diff-modified {
    background-color: rgba(234, 179, 8, 0.3);
    color: #ca8a04;
    padding: 0 2px;
    border-radius: 2px;
}

[data-theme='dark'] .diff-added {
    background-color: rgba(74, 222, 128, 0.25);
    color: #4ade80;
}

[data-theme='dark'] .diff-deleted {
    background-color: rgba(248, 113, 113, 0.25);
    color: #f87171;
}

[data-theme='dark'] .diff-modified {
    background-color: rgba(250, 204, 21, 0.25);
    color: #fbbf24;
}

.rules-diff {
    line-height: 1.6;
}

/* Pagination */
.pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 0.5rem;
    margin-top: 2rem;
    flex-wrap: wrap;
}

.pagination-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 40px;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition-interactive);
}

.pagination-btn:hover:not(:disabled) {
    background-color: var(--bg-tertiary);
    border-color: var(--accent-primary);
}

.pagination-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.pagination-btn.active {
    background-color: var(--accent-primary);
    border-color: var(--accent-primary);
    color: white;
}

.pagination-ellipsis {
    color: var(--text-muted);
    padding: 0 0.25rem;
}

/* No Results */
.no-results {
    text-align: center;
    padding: 3rem 2rem;
    color: var(--text-secondary);
}

.no-results i {
    font-size: 3rem;
    margin-bottom: 1rem;
    color: var(--text-muted);
}

.no-results h3 {
    font-size: 1.25rem;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
}

/* Responsive Search */
@media (max-width: 768px) {
    .header-search-form {
        margin: 0.5rem 0;
        max-width: 100%;
        order: 3;
        width: 100%;
        flex-wrap: wrap;
    }

    .header-search-form .search-input-wrapper {
        flex: 1 1 100%;
    }

    .header-search-form .search-btn {
        flex: 1;
    }

    .card-grid {
        grid-template-columns: 1fr;
    }
}

/* Home Main */
.home-main {
    padding-bottom: 4rem;
}

/* Decks Section */
.decks-section {
    margin-bottom: 2rem;
}

.section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.5rem;
}

.section-header h2 {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 1.5rem;
    color: var(--text-primary);
}

.section-header h2 i {
    color: var(--accent-primary);
}

.btn-sm {
    padding: 0.5rem 1rem;
    font-size: 0.875rem;
    width: auto;
}

/* Decks Grid */
.decks-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1.25rem;
}

/* Deck Card */
.deck-card {
    background-color: var(--bg-secondary);
    border: 2px solid var(--border-color);
    border-radius: 12px;
    padding: 1.25rem;
    cursor: pointer;
    transition: var(--transition-interactive);
    position: relative;
    overflow: hidden;
}

/* Deck / collection tile with a faded card-art background (highest-CMC member card).
   The art is a real <img> in a .card-art-crop layer, not a background-image: our repo
   serves WHOLE cards, so the art window has to be cropped out, and cover+center on a full
   card would frame the type line and rules text instead of the art. These tiles are much
   wider than they are tall, so they need their own crop numbers — that is exactly what the
   custom properties on .card-art-crop are for. */
.deck-card .card-art-crop,
.collection-card .card-art-crop {
    /* ~2.6:1 tile: scale the card so its art band spans the width, then slide the band up.
       Wider box than the 4:3 set tile, so the card is scaled harder and offset less. */
    --art-w: 100%;
    --art-h: 305%;
    --art-x: 0%;
    --art-y: -11.8%;
    --art-opacity: 0.4;
    z-index: 0;
    pointer-events: none;
}

/* Keep tile text crisp over the more-visible art: a scrim from the tile colour. */
.deck-card.has-background::after,
.collection-card.has-background::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to right,
        color-mix(in srgb, var(--bg-secondary) 82%, transparent) 0%,
        color-mix(in srgb, var(--bg-secondary) 55%, transparent) 55%,
        color-mix(in srgb, var(--bg-secondary) 30%, transparent) 100%
    );
    z-index: 0;
    border-radius: 10px;
    pointer-events: none;
}

/* Lift the tile's real content above the art layer. `:not(.card-art-crop)` matters: the art
   layer is itself a direct child, and a blanket `> *` re-positions it to relative — which
   collapses it to a 0-height inline box, so the art silently never renders. */
.deck-card.has-background > *:not(.card-art-crop),
.collection-card.has-background > *:not(.card-art-crop) {
    position: relative;
    z-index: 1;
}

.deck-card:hover {
    border-color: var(--accent-primary);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.deck-card.selected {
    border-color: var(--accent-primary);
    background-color: rgba(2, 119, 189, 0.1);
}

[data-theme='dark'] .deck-card.selected {
    background-color: rgba(129, 140, 248, 0.15);
}

.deck-card-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 0.75rem;
}

.deck-name {
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    word-break: break-word;
}

.deck-select-indicator {
    width: 20px;
    height: 20px;
    border: 2px solid var(--border-color);
    border-radius: 4px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: var(--transition-interactive);
}

.deck-card.selected .deck-select-indicator {
    background-color: var(--accent-primary);
    border-color: var(--accent-primary);
    color: white;
}

.deck-select-indicator i {
    font-size: 0.75rem;
    opacity: 0;
}

.deck-card.selected .deck-select-indicator i {
    opacity: 1;
}

/* Deck Colors */
.deck-colors {
    display: flex;
    gap: 0.375rem;
    margin-bottom: 0.75rem;
}

.mana-symbol {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    font-weight: 700;
    color: white;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.mana-w {
    background: linear-gradient(135deg, #f9faf4 0%, #e6e3d4 100%);
    color: #333;
}
.mana-u {
    background: linear-gradient(135deg, #0e68ab 0%, #0a4f82 100%);
}
.mana-b {
    background: linear-gradient(135deg, #393431 0%, #1a1718 100%);
}
.mana-r {
    background: linear-gradient(135deg, #d3202a 0%, #a31b23 100%);
}
.mana-g {
    background: linear-gradient(135deg, #00733e 0%, #005a30 100%);
}
.mana-c {
    background: linear-gradient(135deg, #cbc9c5 0%, #9e9c99 100%);
    color: #333;
}

/* Inline mana pips for rendered mana costs */
.mana-pip {
    display: inline-flex;
    width: 18px;
    height: 18px;
    font-size: 0.68rem;
    margin-right: 2px;
    vertical-align: middle;
}

/* Deck Formats */
.deck-formats {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    margin-bottom: 0.75rem;
}

.format-tag {
    font-size: 0.6875rem;
    padding: 0.25rem 0.5rem;
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    border-radius: 4px;
    text-transform: uppercase;
    font-weight: 500;
    letter-spacing: 0.025em;
}

/* Deck Cost */
.deck-cost {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.deck-cost i {
    color: var(--accent-secondary);
}

.deck-cost-value {
    font-weight: 600;
    color: var(--text-primary);
}

/* Empty Decks State */
.empty-decks {
    text-align: center;
    padding: 3rem 2rem;
    color: var(--text-secondary);
}

.empty-decks i {
    font-size: 3rem;
    margin-bottom: 1rem;
    color: var(--text-muted);
}

.empty-decks h3 {
    font-size: 1.25rem;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
}

.empty-decks p {
    margin-bottom: 1.5rem;
}

/* Header Brand Clickable */
.header-brand-clickable {
    cursor: pointer;
    transition: color var(--transition-speed);
}

.header-brand-clickable:hover {
    color: var(--accent-primary-hover);
}

/* Collections Section */
.collections-section {
    margin-top: 2.5rem;
    margin-bottom: 2rem;
}

.collections-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1.25rem;
}

/* Collection Card */
.collection-card {
    background-color: var(--bg-secondary);
    border: 2px solid var(--border-color);
    border-radius: 12px;
    padding: 1.25rem;
    cursor: pointer;
    transition: var(--transition-interactive);
    position: relative;
    overflow: hidden;
}

/* (Faded card-art background is handled by the shared .has-background rule above.) */

.collection-card:hover {
    border-color: var(--accent-primary);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
}

.collection-card-header {
    margin-bottom: 1rem;
}

.collection-name {
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
}

.collection-stats {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.collection-stat {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.collection-stat i {
    width: 16px;
    color: var(--accent-secondary);
}

.stat-label {
    color: var(--text-secondary);
}

.stat-value {
    font-weight: 600;
    color: var(--text-primary);
}

/* Empty Collections State */
.empty-collections {
    text-align: center;
    padding: 3rem 2rem;
    color: var(--text-secondary);
}

.empty-collections i {
    font-size: 3rem;
    margin-bottom: 1rem;
    color: var(--text-muted);
}

.empty-collections h3 {
    font-size: 1.25rem;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
}

.empty-collections p {
    margin-bottom: 1.5rem;
}

/* Collection card actions (rename / delete) */
.collection-card-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
}

.collection-actions,
.deck-actions {
    display: flex;
    gap: 0.25rem;
    flex-shrink: 0;
}

/* Small icon button — reused by collection actions, qty steppers, removes */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    padding: 0 0.4rem;
    background-color: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    transition: var(--transition-interactive);
}

.icon-btn:hover {
    background-color: var(--bg-tertiary);
    color: var(--accent-primary);
}

.collection-delete:hover,
.card-row-remove:hover,
.deck-delete:hover {
    color: var(--error-color);
}

/* Collection detail — cards inside a collection (rendered into the grid, full width) */
.collection-detail {
    grid-column: 1 / -1;
}

.collection-detail-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

/* Keep header controls at their natural size so they don't squeeze (which made
   a button's label wrap to two lines); the header wraps to a new row instead. */
.collection-detail-header .btn,
.collection-detail-header .sort-control {
    flex-shrink: 0;
}

.collection-detail-header h3 {
    margin: 0;
    font-size: 1.25rem;
    color: var(--text-primary);
}

.collection-detail-meta {
    margin-left: auto;
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

.collection-card-filter {
    padding: 0.35rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.9rem;
    max-width: 180px;
}

.collection-back {
    flex-shrink: 0;
}

.collection-detail-cards {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.collection-card-row {
    display: grid;
    /* 12 tracks: select, name, set, condition, qty, price, foil, signed, deck, move, edit,
       remove. One short and the trash button wrapped onto a row of its own. */
    grid-template-columns: auto 1fr repeat(10, auto);
    align-items: center;
    gap: 1rem;
    padding: 0.6rem 0.9rem;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    transition: border-color var(--transition-speed);
}

.collection-card-row:hover {
    border-color: var(--accent-primary);
}

.card-row-name {
    font-weight: 600;
    color: var(--text-primary);
}

.card-row-name .fa-star {
    color: var(--accent-secondary);
    font-size: 0.8em;
}

.card-row-set {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.card-row-cond {
    color: var(--text-secondary);
    font-size: 0.78rem;
    min-width: 2.5rem;
    text-align: center;
}

/* "In decks" badge (P5 #508): copies of this card tied up in physical decks.
   `.short` warns when more copies are committed to decks than are owned. */
.card-row-used {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--accent-primary);
    border: 1px solid var(--accent-primary);
    border-radius: 0.6rem;
    padding: 0 0.35rem;
    white-space: nowrap;
    vertical-align: middle;
    opacity: 0.9;
}
.card-row-used.short {
    color: var(--danger, #c0392b);
    border-color: var(--danger, #c0392b);
}

/* Card-art thumbnail in collection rows */
.card-row-thumb,
.card-row-thumb.card-art-crop {
    /* Same contract as .brx-tile-art: a sized inline box that hosts the .card-art-crop image. */
    position: relative;
    inset: auto;
    display: inline-block;
    width: 2.4rem;
    height: 1.7rem;
    overflow: hidden;
    border-radius: 3px;
    vertical-align: middle;
    margin-right: 0.5rem;
    --art-opacity: 1;
}

/* Keyboard-shortcuts help */
#shortcuts-help kbd {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    border: 1px solid var(--border-color);
    border-bottom-width: 2px;
    border-radius: 5px;
    background: var(--bg-tertiary);
    font-family: monospace;
    font-size: 0.8rem;
    color: var(--text-primary);
}

/* Floating card hover-preview */
.card-hover-preview {
    position: fixed;
    width: 240px;
    border-radius: 12px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
    z-index: 9999;
    pointer-events: none;
    display: none;
    background: var(--bg-secondary);
}

/* Conditional formatting: value band cue (left border) on collection rows */
.collection-card-row.value-mid {
    border-left: 3px solid color-mix(in srgb, var(--accent-primary, #0277bd) 45%, transparent);
}
.collection-card-row.value-high {
    border-left: 3px solid color-mix(in srgb, var(--success-color, #2e7d32) 60%, transparent);
}
.collection-card-row.value-premium {
    border-left: 3px solid var(--accent-secondary, #c79b3b);
}

/* Active state for the per-row foil/signed toggle buttons */
.card-row-foil.active,
.card-row-signed.active {
    color: var(--accent-secondary, #c79b3b);
}
.card-row-foil:not(.active),
.card-row-signed:not(.active) {
    opacity: 0.4;
}

.card-row-qty {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.qty-value {
    min-width: 1.5rem;
    text-align: center;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.card-row-price {
    min-width: 4rem;
    text-align: right;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.card-row-price .price-up {
    color: var(--success-color, #2e7d32);
    font-size: 0.7rem;
}
.card-row-price .price-down {
    color: var(--danger-color, #c0392b);
    font-size: 0.7rem;
}

/* Search result card actions (Details / Add) */
.card-actions {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.card-actions .btn {
    flex: 1;
}

/* Card detail view */
.card-detail {
    max-width: 900px;
    margin: 0 auto;
}

.card-detail-back {
    margin-bottom: 1rem;
}

.card-detail-top {
    display: flex;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.card-detail-art {
    width: 240px;
    max-width: 100%;
    border-radius: 12px;
    align-self: flex-start;
}

.card-detail-main {
    flex: 1;
    min-width: 260px;
}

.card-detail-name {
    margin: 0 0 1rem;
    color: var(--text-primary);
}

.card-detail-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.detail-qty-label {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.detail-qty {
    width: 3.5rem;
    padding: 0.35rem 0.4rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.9rem;
}

.detail-foil-label {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
    cursor: pointer;
}

.card-detail-usage {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.85rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.card-detail-usage .usage-deck {
    padding: 0.15rem 0.5rem;
    border-radius: var(--border-radius);
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

.printing-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.printing-chip {
    padding: 0.25rem 0.6rem;
    border-radius: 999px;
    border: 1px solid var(--border-color);
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.78rem;
    transition: var(--transition-interactive);
}

.printing-chip:hover {
    color: var(--accent-primary);
    border-color: var(--accent-primary);
}

.card-detail-note {
    color: var(--success-color);
    font-size: 0.85rem;
}

.card-detail-fields {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 1rem;
}

.detail-row {
    display: flex;
    gap: 0.75rem;
}

.detail-label {
    min-width: 90px;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.detail-value {
    color: var(--text-primary);
}

.detail-rules {
    background-color: var(--bg-tertiary);
    border-radius: 8px;
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
}

.detail-rules h4 {
    margin: 0.5rem 0 0.25rem;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-secondary);
}

.detail-rules h4:first-child {
    margin-top: 0;
}

.detail-rules p {
    margin: 0;
    white-space: pre-wrap;
    color: var(--text-primary);
}

.detail-flavor {
    font-style: italic;
    color: var(--text-secondary);
}

.detail-section {
    margin-top: 1.5rem;
}

.detail-section h4 {
    margin: 0 0 0.5rem;
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 0.35rem;
}

.detail-count {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.85rem;
}

.detail-section ul {
    margin: 0;
    padding-left: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.detail-section li {
    color: var(--text-primary);
}

.combo-cards {
    font-weight: 600;
}

.detail-card-link {
    color: var(--accent-primary);
    cursor: pointer;
}

.detail-card-link:hover {
    text-decoration: underline;
}

.note-source {
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* Curated notes (FR-CARD-8): one <details> per source, the heading doubles as the toggle */
details.detail-notes > summary {
    list-style: none;
    cursor: pointer;
}

details.detail-notes > summary::-webkit-details-marker {
    display: none;
}

details.detail-notes > summary h4::before {
    content: '\25B8';
    display: inline-block;
    width: 1.1em;
    color: var(--text-muted);
    transition: transform 0.15s;
}

details.detail-notes[open] > summary h4::before {
    transform: rotate(90deg);
}

.cycle-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.75rem;
    margin-top: 0.25rem;
}

.cycle-element {
    display: inline-block;
    min-width: 1.4em;
    padding: 0 0.35em;
    border-radius: 4px;
    background: var(--bg-tertiary);
    color: var(--text-muted);
    font-size: 0.8rem;
    text-align: center;
}

/* Card-detail modal (shared, opened from search / collections / decks) */
.card-detail-content {
    max-width: 860px;
    padding: 0;
}

.card-detail-scroll {
    overflow-y: auto;
    max-height: 90vh;
    padding: 1.5rem;
}

.card-detail-scroll .card-detail {
    max-width: none;
}

.card-detail-close {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    z-index: 2;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 50%;
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 1rem;
    transition: var(--transition-interactive);
}

.card-detail-close:hover {
    color: var(--text-primary);
    background-color: var(--border-color);
}

.card-detail-nav {
    position: absolute;
    top: 0.6rem;
    left: 0.6rem;
    z-index: 2;
    display: flex;
    gap: 0.25rem;
}

.cd-nav {
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 50%;
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 1.1rem;
    line-height: 1;
    transition: var(--transition-interactive);
}

.cd-nav:hover:not(:disabled) {
    color: var(--accent-primary);
    background-color: var(--border-color);
}

.cd-nav:disabled {
    opacity: 0.4;
    cursor: default;
}

.hand-cards {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.hand-card {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.7rem;
    border-radius: var(--border-radius);
    background-color: var(--bg-tertiary);
    border-left: 3px solid var(--border-color);
    min-width: 9rem;
}

.hand-card[data-color='W'] {
    border-left-color: #e9e3c8;
}
.hand-card[data-color='U'] {
    border-left-color: #3b7cc0;
}
.hand-card[data-color='B'] {
    border-left-color: #6b6b6b;
}
.hand-card[data-color='R'] {
    border-left-color: #d3492e;
}
.hand-card[data-color='G'] {
    border-left-color: #3c9d57;
}

.hand-card-name {
    flex: 1;
    font-size: 0.9rem;
    color: var(--text-primary);
}

.hand-card-cost {
    display: inline-flex;
    gap: 2px;
}

.hand-note {
    color: var(--text-secondary);
    font-size: 0.85rem;
    margin: 0 0 0.75rem;
}

.decks-controls {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.deck-filter-input {
    flex: 1;
    min-width: 12rem;
    max-width: 22rem;
    padding: 0.45rem 0.7rem;
    border-radius: var(--border-radius);
    border: 1px solid var(--border-color);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.9rem;
}

.deck-filter-input:focus {
    outline: none;
    border-color: var(--accent-primary);
}

.deck-format-badge {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    vertical-align: middle;
}

.deck-format-badge[hidden] {
    display: none;
}

.collections-summary {
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 600;
    width: 100%;
}

/* Clickable card affordances (open the detail modal) */
.card-row-name,
.card-stack-item.card-clickable {
    cursor: pointer;
}

.card-row-name:hover {
    color: var(--accent-primary);
}

/* Search results sort bar */
.results-bar {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-bottom: 0.85rem;
}

.results-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.results-filters {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    flex-wrap: wrap;
    padding: 0.55rem 0.7rem;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
}

.results-bar .results-count {
    margin: 0;
    text-align: left;
}

.color-filter {
    display: flex;
    gap: 0.3rem;
    flex-wrap: wrap;
}

.rarity-filter,
.type-filter,
.cmc-filter {
    padding-left: 0.55rem;
    border-left: 1px solid var(--border-color);
}

.color-chip {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 1px solid var(--border-color);
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    font-weight: 600;
    font-size: 0.8rem;
    cursor: pointer;
    transition: var(--transition-interactive);
}

.color-chip.active {
    border-color: var(--accent-primary);
    color: var(--text-primary);
    background-color: var(--bg-secondary);
    box-shadow: inset 0 0 0 2px var(--accent-primary);
}

/* Type chips carry word labels, so they're pill-shaped rather than round. */
.type-chip {
    width: auto;
    height: 26px;
    padding: 0 0.6rem;
    border-radius: 13px;
    font-size: 0.75rem;
}

.cmc-filter {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    color: var(--text-secondary);
    font-size: 0.8rem;
    font-weight: 600;
}

.cmc-input {
    width: 3.2rem;
    height: 26px;
    padding: 0 0.4rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 0.8rem;
}

.cmc-dash {
    color: var(--text-secondary);
}

.sort-control {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.sort-control select {
    padding: 0.35rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
}

/* Multi-level sort builder (anchors its popover to the sort-more button) */
.sort-more-control {
    position: relative;
    display: inline-flex;
}

.sort-more-btn.active {
    border-color: var(--accent-primary);
    color: var(--accent-primary);
}

.sort-more-count {
    font-weight: 600;
}

.sort-menu {
    min-width: 250px;
}

.sort-primary {
    padding: 0.32rem 0.4rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.sort-level {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.28rem 0.15rem;
}

.sort-level-num {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.sort-level-col {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0.3rem 0.4rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
}

.sort-level-dir {
    flex: 0 0 auto;
    white-space: nowrap;
}

.sort-level-add {
    margin-top: 0.3rem;
}

.sort-hint {
    margin: 0.35rem 0.4rem 0.15rem;
    font-size: 0.78rem;
    color: var(--text-secondary);
}

/* Conditional formatting — editor popover + row highlights on the results table */
.format-control {
    position: relative;
    display: inline-flex;
}

.format-btn.active {
    border-color: var(--accent-primary);
    color: var(--accent-primary);
}

.format-count {
    font-weight: 600;
}

.format-menu {
    min-width: 300px;
}

.cf-rule {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.28rem 0.15rem;
}

.cf-rule select,
.cf-rule input {
    padding: 0.28rem 0.35rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    min-width: 0;
}

.cf-rule .cf-field {
    flex: 1 1 auto;
}

.cf-rule .cf-value {
    flex: 1 1 4rem;
    width: 4rem;
}

.cf-rule .cf-op,
.cf-rule .cf-color {
    flex: 0 0 auto;
}

.cf-add {
    margin-top: 0.3rem;
}

/* Row highlight tints (left border + subtle background) — one per palette colour. */
.results-table tr.cf-red {
    background-color: color-mix(in srgb, #e53935 14%, transparent);
    box-shadow: inset 3px 0 0 #e53935;
}
.results-table tr.cf-orange {
    background-color: color-mix(in srgb, #fb8c00 16%, transparent);
    box-shadow: inset 3px 0 0 #fb8c00;
}
.results-table tr.cf-yellow {
    background-color: color-mix(in srgb, #fdd835 20%, transparent);
    box-shadow: inset 3px 0 0 #fbc02d;
}
.results-table tr.cf-green {
    background-color: color-mix(in srgb, #43a047 16%, transparent);
    box-shadow: inset 3px 0 0 #43a047;
}
.results-table tr.cf-blue {
    background-color: color-mix(in srgb, #1e88e5 15%, transparent);
    box-shadow: inset 3px 0 0 #1e88e5;
}
.results-table tr.cf-purple {
    background-color: color-mix(in srgb, #8e24aa 16%, transparent);
    box-shadow: inset 3px 0 0 #8e24aa;
}

/* Small colour swatch on the rule's colour picker. */
.cf-swatch-red {
    border-left: 4px solid #e53935 !important;
}
.cf-swatch-orange {
    border-left: 4px solid #fb8c00 !important;
}
.cf-swatch-yellow {
    border-left: 4px solid #fbc02d !important;
}
.cf-swatch-green {
    border-left: 4px solid #43a047 !important;
}
.cf-swatch-blue {
    border-left: 4px solid #1e88e5 !important;
}
.cf-swatch-purple {
    border-left: 4px solid #8e24aa !important;
}

/* Deck MRU quick-switch bar */
.deck-mru-bar:not(:empty) {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    padding: 0.4rem 1rem;
    border-bottom: 1px solid var(--border-color);
}
.deck-mru-label {
    color: var(--text-secondary);
    font-size: 0.8rem;
    font-weight: 600;
}
.deck-mru-chip {
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0.2rem 0.6rem;
    font-size: 0.8rem;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    background-color: var(--bg-secondary);
    color: var(--text-secondary);
    cursor: pointer;
}
.deck-mru-chip:hover {
    border-color: var(--accent-primary);
    color: var(--accent-primary);
}
.deck-mru-chip.active {
    border-color: var(--accent-primary);
    color: var(--accent-primary);
    font-weight: 600;
}

/* Bookmark toggle on result cards */
.card-bookmark.active {
    color: var(--accent-secondary, #c79b3b);
    border-color: var(--accent-secondary, #c79b3b);
}

/* Saved-filter control (results bar) */
.saved-filter-control {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.saved-filter-select {
    padding: 0.35rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    max-width: 12rem;
}

/* Deck-view inline card-search dropdown */
#deck-search-form .search-input-wrapper {
    position: relative;
}

.deck-search-results {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 50;
    max-height: 360px;
    overflow-y: auto;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: var(--shadow-lg);
    display: none;
}

.deck-search-head {
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.4rem 0.75rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
    background-color: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
}

.deck-search-row {
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-color);
}

.deck-search-row:last-child {
    border-bottom: none;
}

.deck-search-add-sb {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.deck-search-name {
    color: var(--text-primary);
    cursor: pointer;
}

.deck-search-name:hover {
    color: var(--accent-primary);
}

/* "Owned only" build-from-collection toggle + owned-count badge */
.deck-search-owned-label {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
    white-space: nowrap;
    cursor: pointer;
}
.deck-search-owned-badge {
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--success-color, #2e7d32);
    background-color: color-mix(in srgb, var(--success-color, #2e7d32) 14%, transparent);
    border-radius: 999px;
    padding: 0.02rem 0.4rem;
    margin-left: 0.35rem;
}

.deck-search-set {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

.deck-search-empty {
    padding: 0.75rem;
    color: var(--text-secondary);
}

/* Deck export modal */
.export-body {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1.25rem 1.5rem;
}

.export-text {
    width: 100%;
    resize: vertical;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    white-space: pre;
}

/* Stats modal: cards the database did not know were left out of the numbers. */
.stats-unknown {
    color: var(--warning-color);
    font-size: 0.85rem;
    margin: -0.25rem 0 0.75rem;
}

.export-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}
/* A long status next to the button ("Added 3 copies across 2 cards. Unresolved: ...") must
   not squeeze the button until its label is clipped; the row wraps and the note takes the
   next line. */
.export-actions > .btn {
    flex-shrink: 0;
}

.export-note {
    color: var(--success-color);
    font-size: 0.85rem;
}

/* Deck stats modal */
.stats-body {
    padding: 1.25rem 1.5rem;
    overflow-y: auto;
    max-height: 80vh;
}

.stats-summary {
    margin: 0 0 1rem;
    color: var(--text-secondary);
}

.stats-section {
    margin-bottom: 1.25rem;
}

.stats-section h4 {
    margin: 0 0 0.5rem;
    color: var(--text-primary);
}

.mana-curve {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.curve-row {
    display: grid;
    grid-template-columns: 2rem 1fr 2rem;
    align-items: center;
    gap: 0.5rem;
}

.curve-label {
    text-align: right;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.curve-bar {
    height: 14px;
    background-color: var(--bg-tertiary);
    border-radius: 7px;
    overflow: hidden;
}

.curve-fill {
    display: block;
    height: 100%;
    background-color: var(--accent-primary);
    border-radius: 7px;
}

/* Per-turn mana requirement: a colour-segmented fill (segments partition the bar by colour) */
.mana-stack {
    display: flex;
    overflow: hidden;
}

.mana-seg {
    height: 100%;
    flex: 0 0 auto;
}

.mana-seg.mana-generic {
    background: linear-gradient(135deg, #b9b6b1 0%, #8f8c88 100%);
}

.stats-note {
    margin: 0.4rem 0 0;
    font-size: 0.78rem;
    color: var(--text-secondary);
}

/* Offline connectivity banner (js/offline.js) — slim fixed bar, high z-index above app chrome. */
.offline-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 3000;
    padding: 0.4rem 0.75rem;
    text-align: center;
    font-size: 0.85rem;
    font-weight: 600;
    color: #3a2c00;
    background-color: #ffca28;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.25);
}

.offline-banner[hidden] {
    display: none;
}

/* Reconnecting + replaying the offline write queue (FR-ACCT-8) — positive, not a warning. */
.offline-banner.syncing {
    color: #06371f;
    background-color: #4caf82;
}

.mana-sources {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.source-row {
    display: grid;
    grid-template-columns: 1.6rem 1fr auto;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
}

.source-row .source-val {
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.source-row .source-demand {
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.curve-val {
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.stat-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.stat-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.6rem;
    background-color: var(--bg-tertiary);
    border-radius: 999px;
    font-size: 0.85rem;
    color: var(--text-primary);
}

/* Deck card qty / remove controls */
.stack-controls {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin-top: 0.35rem;
}

.stack-qty {
    min-width: 1.25rem;
    text-align: center;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

@media (max-width: 600px) {
    .collection-card-row {
        grid-template-columns: auto 1fr auto auto;
        gap: 0.6rem;
    }

    .collection-card-row .card-row-set {
        display: none;
    }
}

/* Reports Section */
.reports-section {
    margin-top: 2.5rem;
    margin-bottom: 2rem;
}

.reports-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 1rem;
}

/* Report Card */
/* Tiles are <button>s (NFR-O-5): they were clickable <div>s, unreachable by keyboard and
   announced as nothing. The resets below undo what a button brings with it. */
.report-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    width: 100%;
    padding: 1.25rem 1rem;
    background-color: var(--bg-secondary);
    border: 2px solid var(--border-color);
    border-radius: 12px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    /* Named rather than `all`: only these change on hover, and `all` also animates properties
       the browser has to recompute layout for (NFR-G-4). */
    transition:
        border-color var(--transition-speed),
        background-color var(--transition-speed),
        box-shadow var(--transition-speed),
        transform var(--transition-speed);
    text-align: center;
}

.report-card:hover {
    border-color: var(--accent-primary);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
    background-color: var(--bg-tertiary);
}

.report-card i {
    font-size: 1.75rem;
    color: var(--accent-primary);
}

.report-card span {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-primary);
    line-height: 1.3;
}

/* Profile Section */
.profile-section {
    margin-top: 2.5rem;
    margin-bottom: 2rem;
}

.profile-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 1rem;
}

/* Profile Card */
.profile-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    width: 100%;
    padding: 1.25rem 1rem;
    background-color: var(--bg-secondary);
    border: 2px solid var(--border-color);
    border-radius: 12px;
    cursor: pointer;
    font: inherit;
    color: inherit;
    transition:
        border-color var(--transition-speed),
        background-color var(--transition-speed),
        box-shadow var(--transition-speed),
        transform var(--transition-speed);
    text-align: center;
}

.profile-card:hover {
    border-color: var(--accent-primary);
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
    background-color: var(--bg-tertiary);
}

.profile-card i {
    font-size: 1.75rem;
    color: var(--accent-primary);
}

.profile-card span {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-primary);
    line-height: 1.3;
}

/* Rules Section */
.rules-section {
    margin-top: 2.5rem;
    margin-bottom: 2rem;
}

.rules-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 1rem;
}

a.report-card {
    text-decoration: none;
    color: inherit;
}

/* Advanced Search Button */
/* In-field control inside the search pill: subtle, icon-only. */
.btn-advanced {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem 0.5rem;
    background-color: transparent;
    border: none;
    color: var(--text-muted);
    border-radius: 6px;
    flex-shrink: 0;
    width: auto;
    font-size: 1rem;
    cursor: pointer;
    transition:
        background-color var(--transition-speed),
        color var(--transition-speed);
}

.btn-advanced:hover {
    background-color: var(--bg-tertiary);
    color: var(--accent-primary);
}

/* Header Title */
.header-title {
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--text-primary);
    flex: 1;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

/* Icon Button */
.btn-icon {
    background: none;
    border: none;
    color: var(--text-secondary);
    font-size: 0.875rem;
    cursor: pointer;
    padding: 0.375rem;
    border-radius: 6px;
    transition: var(--transition-interactive);
}

.btn-icon:hover {
    background-color: var(--bg-tertiary);
    color: var(--accent-primary);
}

/* Language Selector Button */
.language-btn {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 0.5rem;
    cursor: pointer;
    transition: var(--transition-interactive);
    height: 48px;
}

.language-btn:hover {
    background: var(--bg-secondary);
    border-color: var(--accent-primary);
}

.lang-flag-icon {
    width: 24px;
    height: 18px;
    object-fit: cover;
    border-radius: 2px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.lang-arrow {
    font-size: 0.625rem;
    color: var(--text-secondary);
    transition: transform var(--transition-speed);
}

.language-btn:hover .lang-arrow {
    color: var(--accent-primary);
}

/* Sign-up: the password rule under the field and the terms line under the button. */
.signup-hint {
    margin: -0.5rem 0 1rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.signup-terms {
    margin: 0.9rem 0 0;
    font-size: 0.85rem;
    color: var(--text-secondary);
    text-align: center;
}

/* Forgotten password: the link under the Sign In button, and the two-step modal that
   reuses the sign-in form's field styling. */
.login-forgot {
    margin: 0.9rem 0 0;
    text-align: center;
    font-size: 0.9rem;
}
.prx-modal {
    max-width: 440px;
    width: 95%;
}
.prx-intro {
    margin: 0 0 1rem;
    color: var(--text-secondary);
}
.prx-step .btn + .btn {
    margin-top: 0.6rem;
}
.prx-step[hidden] {
    display: none;
}

/* Login Language Button - positioned in top right of login view */
.login-language-btn {
    position: fixed;
    top: 1rem;
    right: 5rem;
    z-index: 10;
    height: 48px;
}

/* Language Modal */
.language-modal-content {
    max-width: 560px;
    width: 95%;
}

.language-modal-content .modal-body {
    padding: 1rem;
}

.language-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
    max-height: 60vh;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 0.25rem;
}

/* Responsive language grid */
@media (max-width: 600px) {
    .language-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 400px) {
    .language-grid {
        grid-template-columns: 1fr;
    }

    .language-modal-content {
        width: 100%;
        max-width: none;
        margin: 0;
        border-radius: 0;
        min-height: 100vh;
    }
}

/* Custom scrollbar for language grid */
.language-grid::-webkit-scrollbar {
    width: 8px;
}

.language-grid::-webkit-scrollbar-track {
    background: var(--bg-tertiary);
    border-radius: 4px;
}

.language-grid::-webkit-scrollbar-thumb {
    background: var(--border-color);
    border-radius: 4px;
}

.language-grid::-webkit-scrollbar-thumb:hover {
    background: var(--text-secondary);
}

.language-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 0.5rem;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 0.8rem;
    cursor: pointer;
    transition: var(--transition-interactive);
    min-width: 0;
}

.language-option:hover,
.language-option:focus {
    background: var(--bg-secondary);
    border-color: var(--accent-primary);
    transform: translateY(-1px);
    outline: none;
}

.language-option:focus {
    box-shadow: 0 0 0 2px var(--accent-primary);
}

.language-option.active {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: white;
}

.language-option.active:focus {
    box-shadow: 0 0 0 2px var(--text-primary);
}

.language-option .lang-flag-icon {
    width: 24px;
    height: 17px;
    flex-shrink: 0;
}

.language-option .lang-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Notification Button */
.notification-btn {
    position: relative;
    font-size: 1.125rem;
}

.notification-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    background-color: var(--error-color);
    color: white;
    font-size: 0.65rem;
    font-weight: 700;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

.notification-badge:empty {
    display: none;
}

/* Toggle Switch */
.toggle-switch {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    cursor: pointer;
}

.toggle-switch input {
    display: none;
}

.toggle-slider {
    position: relative;
    width: 44px;
    height: 24px;
    background-color: var(--bg-tertiary);
    border-radius: 12px;
    transition: background-color var(--transition-speed);
}

.toggle-slider::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    background-color: white;
    border-radius: 50%;
    transition: transform var(--transition-speed);
    box-shadow: var(--shadow-sm);
}

.toggle-switch input:checked + .toggle-slider {
    background-color: var(--accent-primary);
}

.toggle-switch input:checked + .toggle-slider::after {
    transform: translateX(20px);
}

.toggle-label {
    font-size: 0.875rem;
    color: var(--text-secondary);
    white-space: nowrap;
}

/* Notifications View */
.notifications-main {
    max-width: 800px;
    margin: 0 auto;
    padding: 1.5rem;
}

.notifications-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.notification-item {
    background-color: var(--bg-secondary);
    border-radius: 12px;
    border-left: 4px solid;
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    transition: box-shadow var(--transition-speed);
}

.notification-item:hover {
    box-shadow: var(--shadow-md);
}

.notification-item.archived {
    opacity: 0.6;
}

.notification-item[data-type='informational'] {
    border-left-color: #3b82f6;
}

.notification-item[data-type='warning'] {
    border-left-color: #f59e0b;
}

.notification-item[data-type='error'] {
    border-left-color: #ef4444;
}

.notification-item[data-type='fatal'] {
    border-left-color: #991b1b;
}

.notification-item[data-type='maintenance'] {
    border-left-color: #6b7280;
}

.notification-header {
    display: flex;
    align-items: flex-start;
    padding: 1rem 1.25rem;
    gap: 0.75rem;
    cursor: pointer;
}

.notification-icon {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
}

.notification-item[data-type='informational'] .notification-icon {
    color: #3b82f6;
}

.notification-item[data-type='warning'] .notification-icon {
    color: #f59e0b;
}

.notification-item[data-type='error'] .notification-icon {
    color: #ef4444;
}

.notification-item[data-type='fatal'] .notification-icon {
    color: #991b1b;
}

.notification-item[data-type='maintenance'] .notification-icon {
    color: #6b7280;
}

.notification-content {
    flex: 1;
    min-width: 0;
}

.notification-meta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.25rem;
}

.notification-type {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.125rem 0.5rem;
    border-radius: 4px;
    background-color: var(--bg-tertiary);
}

.notification-item[data-type='informational'] .notification-type {
    color: #3b82f6;
}

/* Light theme only: #3b82f6 on the pale --bg-tertiary badge tint is 3.1:1 (WCAG AA fail).
   A darker blue clears it (~5.6:1); dark theme keeps the lighter blue for its dark tint. */
:root:not([data-theme='dark']) .notification-item[data-type='informational'] .notification-type {
    color: #1d4ed8;
}

.notification-item[data-type='warning'] .notification-type {
    color: #f59e0b;
}

.notification-item[data-type='error'] .notification-type {
    color: #ef4444;
}

.notification-item[data-type='fatal'] .notification-type {
    color: #991b1b;
}

.notification-item[data-type='maintenance'] .notification-type {
    color: #6b7280;
}

.notification-timestamp {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.notification-title {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
}

.notification-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.notification-actions .btn-icon {
    color: var(--text-muted);
}

.notification-actions .btn-icon:hover {
    color: var(--text-primary);
}

.notification-expand {
    transition: transform var(--transition-speed);
}

.notification-item.expanded .notification-expand {
    transform: rotate(180deg);
}

.notification-body {
    display: none;
    padding: 0 1.25rem 1rem 3.25rem;
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.6;
}

.notification-item.expanded .notification-body {
    display: block;
}

.notification-body p {
    margin-bottom: 0.75rem;
}

.notification-body p:last-child {
    margin-bottom: 0;
}

.notification-body ul,
.notification-body ol {
    margin: 0.5rem 0;
    padding-left: 1.25rem;
}

.notification-body li {
    margin-bottom: 0.25rem;
}

.notification-body strong {
    color: var(--text-primary);
}

.notification-body a {
    color: var(--accent-primary);
    text-decoration: none;
}

.notification-body a:hover {
    text-decoration: underline;
}

.notifications-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 4rem 2rem;
    color: var(--text-muted);
    text-align: center;
}

.notifications-empty i {
    font-size: 3rem;
    margin-bottom: 1rem;
}

/* Advanced Search Form */
.advanced-search-main {
    max-width: 900px;
}

.advanced-search-form {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 2rem;
}

.search-filters-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 1.5rem;
    margin-bottom: 2rem;
}

.filter-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    border: none;
    padding: 0;
    margin: 0;
}

.filter-group label,
.filter-group legend {
    font-weight: 500;
    color: var(--text-primary);
    font-size: 0.875rem;
}

.filter-group input,
.filter-group select {
    padding: 0.75rem 1rem;
    font-size: 0.9375rem;
    border: 2px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    transition: border-color var(--transition-speed);
}

.filter-group input:focus,
.filter-group select:focus {
    outline: none;
    border-color: var(--accent-primary);
}

.filter-group input::placeholder {
    color: var(--text-muted);
}

/* Color Checkboxes */
.color-checkboxes {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.color-checkbox {
    cursor: pointer;
    display: flex;
    align-items: center;
}

.color-checkbox input {
    display: none;
}

.color-checkbox .mana-symbol {
    opacity: 0.4;
    transition:
        opacity var(--transition-speed),
        transform var(--transition-speed);
}

.color-checkbox input:checked + .mana-symbol {
    opacity: 1;
    transform: scale(1.15);
    box-shadow: 0 0 0 2px var(--accent-primary);
}

/* Edition (Set) multi-select filter */
.edition-select {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.edition-filter {
    width: 100%;
}

.edition-list {
    max-height: 180px;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    padding: 0.25rem;
    background-color: var(--bg-secondary);
}

.edition-option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.28rem 0.4rem;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--text-primary);
}

.edition-option:hover {
    background-color: var(--bg-tertiary);
}
/* The shared .brx-set-icon is sized for the Sets index table (26px); these rows are 0.9rem,
   so scale it down here. The theme-aware inversion stays inherited from that class rather
   than being restated. `flex: 0 0` keeps every label's text starting at the same x, so the
   list still reads as a column when a set has no symbol file. */
.edition-icon {
    width: 18px;
    height: 18px;
    flex: 0 0 18px;
}

.edition-option input {
    accent-color: var(--accent-primary);
}

.edition-empty {
    margin: 0;
    padding: 0.4rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Range Inputs */
.range-inputs {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.range-inputs input {
    flex: 1;
    min-width: 0;
}

.range-inputs span {
    color: var(--text-muted);
    font-size: 0.875rem;
}

/* Advanced Search Actions */
.advanced-search-actions {
    display: flex;
    justify-content: flex-end;
    gap: 1rem;
}

.advanced-search-actions .btn {
    width: auto;
    padding: 0.75rem 1.5rem;
}

/* Loading Message */
.loading-message {
    text-align: center;
    padding: 3rem 2rem;
    color: var(--text-secondary);
    font-size: 1.125rem;
}

.loading-message i {
    margin-right: 0.5rem;
}

/* Responsive Decks */
@media (max-width: 768px) {
    .section-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
    }

    .decks-grid {
        grid-template-columns: 1fr;
    }
}

/* App Footer */
/* The footer is fixed, so the last strip of every page renders underneath it. Signed-in views
   already clear it — `body.has-app-nav` reserves 64/76px for the nav pill, which is taller and
   sits in the same band — but signed-out ones reserved nothing, so the final ~50px of the
   landing, login and legal pages were permanently occluded (measured: content ran to the
   viewport bottom while the footer started 50px above it, with nothing left to scroll). Reserve
   the footer's own height as the floor (`--footer-clear`), and trim the 100vh floors by the same
   amount so the reservation does not stack into a dead scroll on short pages. */
body:not(.has-app-nav) {
    padding-bottom: var(--footer-clear);
}

body:not(.has-app-nav) .view,
body:not(.has-app-nav) .login-container {
    min-height: calc(100vh - var(--footer-clear));
}

.app-footer {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem 1rem;
    z-index: 100;
    user-select: none;
}

/* On signed-in views the fixed floating bottom-nav pill (.app-nav, z-index 900) sits over the
   CENTER of the footer (z-index 100), occluding the centered "Free forever · Support us" link —
   WCAG 2.2 target-size fails and the link is barely clickable. Hide just that occluded middle
   link while the app-nav is present; the flanking Discord (left) and copyright/Legal (right)
   links stay clear of the pill and clickable — importantly #show-legal is the ONLY entry point
   to the Legal page, so the footer can't be hidden wholesale on signed-in views. */
body.has-app-nav .support-footer-link {
    display: none;
}

/* Right-hand footer column: copyright on top, the fan-content disclaimer beneath it. Stacked
   and right-aligned so it fits the single-row footer without disrupting the flex layout, and
   stays clear of the centered app-nav pill. */
.footer-legal {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.1rem;
    min-width: 0;
    text-align: right;
}

.copyright,
.copyright-link {
    color: var(--text-muted);
    font-size: 0.75rem;
    text-decoration: none;
    transition: color var(--transition-speed);
}

.copyright-link:hover {
    color: var(--accent-primary);
}

.discord-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.875rem;
    cursor: pointer;
    transition: color var(--transition-speed);
}

.discord-link:hover {
    color: #5865f2;
}

.discord-link i {
    font-size: 1.25rem;
}

/* WCAG 2.2 target-size (AA): the footer support link rendered only ~22px tall. This raises it
   to the 24px minimum height; the other half of the criterion — ≥24px of safe spacing to the
   adjacent footer links (currently ~15.6px) — needs a footer-layout change and is still
   allowlisted in a11y.spec.js's KNOWN map. */
.support-footer-link {
    min-height: 24px;
    padding-block: 2px;
}

/* Legal Page */
/* Not-found view */
.nfx-body {
    max-width: 480px;
    margin: 3rem auto;
    padding: 0 1.5rem;
    text-align: center;
}
.nfx-icon {
    font-size: 3rem;
    color: var(--text-muted);
    margin-bottom: 1rem;
}
.nfx-body h1 {
    margin: 0 0 0.5rem;
}
.nfx-body p {
    color: var(--text-secondary);
}
.nfx-path code {
    word-break: break-all;
}
.nfx-actions {
    display: flex;
    justify-content: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
}
.nfx-actions .btn {
    width: auto;
    text-decoration: none;
}

.legal-container {
    max-width: 900px;
    margin: 0 auto;
    padding: 2rem 1.5rem 4rem;
    min-height: 100vh;
    background-color: var(--bg-primary);
}

.legal-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 2rem;
}

.legal-header h2 {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
}

.btn-back {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    background-color: transparent;
    border: none;
    color: var(--text-secondary);
    font-size: 0.875rem;
    cursor: pointer;
    transition: color var(--transition-speed);
}

.btn-back:hover {
    color: var(--text-primary);
}

/* The legal hub is continuous prose, so the COLUMN is capped at the measure plus the card's
   own padding (NFR-G-3) rather than letting a 1440px screen set the line length. Capping the
   text inside a full-width card instead would have left every card half empty on the right. */
.legal-sections {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    max-width: calc(var(--measure) + 2 * var(--space-6));
    margin-inline: auto; /* centred under the centred page header, not hugging the left edge */
}

.legal-card {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    box-shadow: var(--shadow-sm);
}

/* ---- Support / pricing page (M11 Phase 0) ---- */
.support-body > .legal-card {
    margin-bottom: 1.25rem;
}
.support-hero {
    text-align: center;
    margin: 0.5rem 0 1.5rem;
}
.support-hero h2 {
    font-size: 1.6rem;
    margin: 0 0 0.4rem;
    color: var(--text-primary);
}
.support-hero p {
    color: var(--text-secondary);
    max-width: 640px;
    margin: 0 auto;
}
.support-status {
    display: inline-block;
    margin-top: 0.8rem;
    padding: 0.4rem 0.9rem;
    border-radius: 999px;
    background: var(--bg-tertiary, var(--bg-secondary));
    border: 1px solid var(--border-color);
    color: var(--text-primary);
}
.support-status i {
    color: #e0245e;
    margin-right: 0.35rem;
}
.support-section-title {
    margin: 1.6rem 0 0.3rem;
    color: var(--text-primary);
}
.support-tiers {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1rem;
    margin: 0.8rem 0 1.4rem;
}
.support-tiers-single {
    grid-template-columns: minmax(220px, 420px);
}
.support-tier {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.support-tier h3 {
    margin: 0;
    color: var(--text-primary);
}
.support-tier-highlight {
    border-color: var(--accent-primary);
    box-shadow: var(--shadow-sm);
}
.support-tier-future {
    border-style: dashed;
}
.support-price .support-amount {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--text-primary);
}
.support-price .support-cadence,
.support-annual {
    color: var(--text-secondary);
    font-size: 0.85rem;
}
.support-perks {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    color: var(--text-secondary);
    font-size: 0.875rem;
}
.support-perks i,
.support-pledge-list i {
    color: var(--accent-primary);
    margin-right: 0.4rem;
}
.support-note {
    color: var(--text-secondary);
    font-size: 0.78rem;
    margin: 0;
}
.support-cta {
    margin-top: auto;
    text-align: center;
}
.support-pledge-list {
    list-style: none;
    padding: 0;
    margin: 0.6rem 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 0.35rem 1rem;
    font-size: 0.875rem;
}
.support-meters {
    width: 100%;
}
.support-tipjar {
    text-align: center;
    color: var(--text-secondary);
    margin: 1.4rem 0 0.6rem;
}
.support-credits-row {
    margin: 0.2rem 0;
    color: var(--text-secondary);
}
.support-credits-mythic {
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--text-primary);
}
.support-credits-foil {
    font-weight: 600;
}
/* ---- Supporter cosmetic palettes (M11 Phase B) — accent overrides layered over
   light/dark. Client-side unlocks by doctrine (cosmetics exempt from server enforcement). */
[data-palette='foil'] {
    --accent-primary: #7c4dff;
    --accent-primary-hover: #5e35b1;
    --accent-secondary: #00bcd4;
}
[data-palette='foil'][data-theme='dark'] {
    --accent-primary: #9575ff;
    --accent-primary-hover: #b39dff;
    --accent-secondary: #26c6da;
}
[data-palette='mythic'] {
    --accent-primary: #d84315;
    --accent-primary-hover: #bf360c;
    --accent-secondary: #ff8f00;
}
[data-palette='mythic'][data-theme='dark'] {
    --accent-primary: #ff7043;
    --accent-primary-hover: #ff8a65;
    --accent-secondary: #ffb300;
}
[data-palette='island'] {
    --accent-primary: #00695c;
    --accent-primary-hover: #004d40;
    --accent-secondary: #0277bd;
}
[data-palette='island'][data-theme='dark'] {
    --accent-primary: #26a69a;
    --accent-primary-hover: #4db6ac;
    --accent-secondary: #29b6f6;
}

/* Supporter badge (profile card, User Voice) */
.uv-badge.uv-supporter,
.supporter-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.05rem 0.5rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    color: #fff;
    background: linear-gradient(120deg, #7c4dff, #00bcd4);
    vertical-align: middle;
}

/* ---- Watchlist + price history (M11 Phase C) ---- */
.wl-toolbar {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    flex-wrap: wrap;
    margin-bottom: 0.8rem;
}
.wl-capacity {
    color: var(--text-secondary);
}
.wl-table .wl-alert {
    width: 4.5rem;
}
.wl-trend {
    color: var(--text-secondary);
}
.wl-up {
    color: #2e7d32;
}
.wl-down {
    color: #c62828;
}
[data-theme='dark'] .wl-up {
    color: #66bb6a;
}
[data-theme='dark'] .wl-down {
    color: #ef5350;
}
.price-spark {
    display: block;
    width: 100%;
    max-width: 560px;
    height: 90px;
}
.price-spark-legend {
    color: var(--text-secondary);
    font-size: 0.8rem;
    margin-top: 0.2rem;
}

.support-redeem {
    margin-top: 1rem;
    padding-top: 0.9rem;
    border-top: 1px dashed var(--border-color);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.support-redeem h4 {
    margin: 0;
    color: var(--text-primary);
}
.support-redeem textarea,
.support-redeem input {
    width: 100%;
}

.legal-card-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.legal-card-header i {
    font-size: var(--font-size-2xl);
    color: var(--accent-primary);
}

.legal-card-header h3 {
    font-size: var(--font-size-xl);
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
}

/* No max-width here: the legal hub caps its whole column (see .legal-sections), and this class
   is reused by the support page's cards, where a measure cap would leave them half empty. */
.legal-card-content {
    color: var(--text-secondary);
    font-size: var(--font-size-xs);
    line-height: 1.6;
}

.legal-card-content p {
    margin: 0 0 var(--space-3);
}

.legal-card-content p:last-child {
    margin-bottom: 0;
}

.legal-card-content ul {
    margin: var(--space-2) 0;
    padding-left: var(--space-6);
}

.legal-card-content li {
    margin-bottom: var(--space-2);
}

.legal-card-content strong {
    color: var(--text-primary);
}

.legal-contact {
    margin-top: 2rem;
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.legal-contact a {
    color: var(--accent-primary);
    text-decoration: none;
}

.legal-contact a:hover {
    text-decoration: underline;
}

/* Deck View */
.deck-main {
    padding-bottom: 4rem;
}

.deck-section {
    margin-bottom: 2rem;
}

.deck-view-colors {
    display: inline-flex;
    gap: 0.2rem;
    vertical-align: middle;
}

/* Locked deck: hide the edit affordances (the lock button stays to toggle back) */
#deck-view.deck-locked #deck-search-form,
#deck-view.deck-locked .stack-controls {
    display: none;
}
#deck-view.deck-locked .card-stack-item {
    cursor: default;
}
#deck-lock-btn.active {
    color: var(--accent-primary);
    border-color: var(--accent-primary);
}

/* Individual card lock (FR-DECK-7): keep the lock button live, disable the mutating controls. */
.card-stack-item.card-locked {
    cursor: default;
}
.card-stack-item.card-locked .stack-dec,
.card-stack-item.card-locked .stack-inc,
.card-stack-item.card-locked .stack-playset,
.card-stack-item.card-locked .stack-move,
.card-stack-item.card-locked .stack-swap,
.card-stack-item.card-locked .stack-remove {
    opacity: 0.35;
    pointer-events: none;
}
.card-stack-item .stack-lock.active {
    color: var(--accent-primary);
}

/* Swap-card modal */
.swap-input {
    width: 100%;
    padding: 0.5rem 0.7rem;
    margin: 0.4rem 0;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
}
.swap-results {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    max-height: 50vh;
    overflow-y: auto;
}
.swap-pick {
    display: flex;
    justify-content: space-between;
    gap: 0.6rem;
    text-align: left;
}
.swap-set {
    color: var(--text-secondary);
    font-size: 0.8rem;
}

/* Drag-drop target highlight when moving a card between main and sideboard */
.deck-section.drop-target {
    outline: 2px dashed var(--accent-primary);
    outline-offset: 4px;
    border-radius: 8px;
    background-color: color-mix(in srgb, var(--accent-primary) 6%, transparent);
}
.card-stack-item[draggable='true'] {
    cursor: grab;
}
/* Floating ghost that follows the finger during a touch drag (FR-DECK-4). */
/* While a touch drag is in flight the fixed bottom chrome must not answer hit-tests: the deck
   drop zones resolve their target with document.elementFromPoint, and a zone whose midpoint
   falls in that band would otherwise hit the footer (z 100) or the app-nav pill (z 900) and the
   drop would silently do nothing. Neither is a drop target, so this costs nothing — and the zone
   behind still highlights, so the finger is not over an unmarked target. It does NOT help a zone
   scrolled fully off-screen; touch drag has no auto-scroll (see docs/analyze/browser-support.md). */
body.touch-dragging .app-footer,
body.touch-dragging .app-nav {
    pointer-events: none;
}

.touch-drag-ghost {
    position: fixed;
    z-index: 3000;
    transform: translate(-50%, -140%);
    padding: 0.35rem 0.6rem;
    border-radius: 6px;
    background-color: var(--accent-primary);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    pointer-events: none;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    max-width: 60vw;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.deck-search-row[draggable='true'] {
    cursor: grab;
}
/* Deck → pool removal target: dropping a deck card here removes it (FR-DECK-4). */
.deck-search-results.drop-remove {
    outline: 2px dashed var(--danger, #e5484d);
    outline-offset: 2px;
    background-color: color-mix(in srgb, var(--danger, #e5484d) 8%, transparent);
}

.deck-section-header {
    display: flex;
    /* Title, count and the filter box share one row on desktop; on a phone the row must be
       allowed to break or the deck name squeezes into a three-line column beside a clipped
       filter input. */
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 0.75rem;
    margin-bottom: 1rem;
    padding-bottom: 0.75rem;
    border-bottom: 2px solid var(--border-color);
}

.deck-section-header h2 {
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.deck-section-header h2 > i {
    color: var(--accent-primary);
}

.deck-section-header h2 .btn-icon {
    font-size: 0.75rem;
    opacity: 0.6;
}

.deck-section-header h2 .btn-icon:hover {
    opacity: 1;
}

.deck-count {
    font-size: 0.875rem;
    color: var(--text-secondary);
    font-weight: 500;
}

.deck-columns {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
}

.deck-columns-2 {
    grid-template-columns: repeat(2, 1fr);
}

.deck-column {
    min-width: 0;
}

.column-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem;
    background-color: var(--bg-secondary);
    border-radius: 8px;
    margin-bottom: 1rem;
    font-weight: 600;
    color: var(--text-primary);
}

.column-header i {
    color: var(--accent-primary);
}

.column-icon {
    font-size: 1rem;
}

.column-header span:last-child {
    margin-left: auto;
    background-color: var(--bg-tertiary);
    padding: 0.25rem 0.5rem;
    border-radius: 4px;
    font-size: 0.75rem;
}

.column-count {
    font-weight: 500;
    color: var(--text-secondary);
}

/* Card Stacks */
.card-stacks {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

.card-stack {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* Hidden by the in-deck card filter (FR-SRCH-6). */
.card-stack-item.filtered-out {
    display: none;
}

.card-stack-item {
    position: relative;
    width: 180px; /* 2.5 inches at ~72dpi scaled down */
    aspect-ratio: 5 / 7; /* 2.5 x 3.5 ratio */
    border-radius: 10px;
    overflow: hidden;
    box-shadow: var(--shadow-md);
    transition:
        transform var(--transition-speed),
        z-index 0s;
    cursor: pointer;
}

.card-stack-item:not(:first-child) {
    margin-top: -220px; /* Fixed overlap showing ~32px of each card */
}

.card-stack-item:hover {
    transform: translateY(10px) translateX(20px) scale(1.02);
    z-index: 100;
    box-shadow: var(--shadow-xl);
}

/* QA-004: on touch / no-hover devices the hover-lift that exposes a card's controls never fires,
   so the inc/dec/remove buttons sit under the overlapping next card and taps hit the card face
   (opening card detail) instead. De-overlap the stack and let each card grow to include its
   control row so every card's buttons are fully visible and directly tappable. Desktop (hover)
   is untouched. */
@media (hover: none) {
    .card-stacks {
        gap: 0.75rem;
    }
    .card-stack-item {
        aspect-ratio: auto;
        overflow: visible;
    }
    .card-stack-item .card-placeholder {
        aspect-ratio: 5 / 7;
        height: auto;
    }
    .card-stack-item:not(:first-child) {
        margin-top: 0.75rem;
    }
}

.card-name-label {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    padding: 0.35rem 0.5rem;
    background: linear-gradient(
        to bottom,
        rgba(0, 0, 0, 0.8) 0%,
        rgba(0, 0, 0, 0.4) 80%,
        transparent 100%
    );
    color: white;
    font-size: 0.7rem;
    font-weight: 600;
    text-align: left;
    z-index: 5;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}

.card-stack-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 10px;
}

.card-stack-item .card-placeholder {
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, var(--bg-tertiary) 0%, var(--bg-secondary) 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    text-align: center;
    border: 2px solid var(--border-color);
    border-radius: 10px;
}

/* Card art on a deck stack: the art_crop under a dark gradient so text stays legible.
   Text is pushed to the bottom so the art shows through the top of the tile. */
.card-stack-item .card-placeholder.has-art {
    background-image:
        linear-gradient(
            to top,
            rgba(0, 0, 0, 0.88) 0%,
            rgba(0, 0, 0, 0.45) 40%,
            rgba(0, 0, 0, 0.12) 100%
        ),
        var(--stack-art);
    background-size: cover;
    background-position: center top;
    background-repeat: no-repeat;
    justify-content: flex-end;
}
.card-placeholder.has-art .card-name-text {
    color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}
.card-placeholder.has-art .card-type-text {
    color: rgba(255, 255, 255, 0.85);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}
.card-placeholder.has-art .card-price-text {
    color: #ffd86b;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}

.card-placeholder .card-name-text {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-primary);
    word-break: break-word;
}

.card-placeholder .card-type-text {
    font-size: 0.625rem;
    color: var(--text-secondary);
    margin-top: 0.25rem;
}

.card-placeholder .card-price-text {
    font-size: 0.65rem;
    font-weight: 600;
    color: var(--accent-secondary);
    margin-top: 0.15rem;
}

/* Card color indicators */
.card-stack-item[data-color='W'] {
    border: 3px solid #f8e7b9;
}
.card-stack-item[data-color='U'] {
    border: 3px solid #0e68ab;
}
.card-stack-item[data-color='B'] {
    border: 3px solid #150b00;
}
.card-stack-item[data-color='R'] {
    border: 3px solid #d3202a;
}
.card-stack-item[data-color='G'] {
    border: 3px solid #00733e;
}
.card-stack-item[data-color='C'] {
    border: 3px solid #cac5c0;
}
.card-stack-item[data-color='M'] {
    border: 3px solid #c9a048;
} /* Multicolor/Gold */

/* Quantity badge */
.card-quantity-badge {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    background-color: rgba(0, 0, 0, 0.8);
    color: white;
    font-size: 0.75rem;
    font-weight: 700;
    padding: 0.25rem 0.5rem;
    border-radius: 4px;
    z-index: 10;
}

/* Sideboard section styling */
.sideboard-section {
    padding-top: 1rem;
}

/* Deck Tools Section */
.deck-tools-section {
    margin-top: 2rem;
}

.deck-tools-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 1rem;
}

/* Empty column state */
.card-stacks:empty::after {
    content: 'No cards';
    display: block;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.875rem;
    padding: 2rem;
    background-color: var(--bg-secondary);
    border-radius: 8px;
    border: 2px dashed var(--border-color);
}

/* Responsive deck view */
@media (max-width: 900px) {
    .deck-columns {
        grid-template-columns: 1fr;
    }

    .card-stack-item {
        width: 150px;
    }

    .card-stack-item:not(:first-child) {
        margin-top: -178px; /* Maintain ~32px visible */
    }
}

@media (max-width: 600px) {
    .card-stack-item {
        width: 120px;
    }

    .card-stack-item:not(:first-child) {
        margin-top: -136px; /* Maintain ~32px visible */
    }
}

/* Modal */
.modal {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}

.modal-backdrop {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
}

.modal-content {
    position: relative;
    background-color: var(--bg-secondary);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-xl);
    width: 100%;
    max-width: 500px;
    max-height: 90vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.modal-content.modal-sm {
    max-width: 400px;
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-5) var(--space-6);
    border-bottom: 1px solid var(--border-color);
}

.modal-header h2 {
    font-size: var(--font-size-xl);
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.modal-header h2 i {
    color: var(--accent-primary);
}

.modal-close {
    background: none;
    border: none;
    color: var(--text-secondary);
    font-size: var(--font-size-xl);
    cursor: pointer;
    padding: var(--space-2);
    border-radius: var(--radius-md);
    transition: var(--transition-interactive);
}

.modal-close:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

.modal-body {
    padding: var(--space-6);
    overflow-y: auto;
    flex: 1;
}

.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-6);
    border-top: 1px solid var(--border-color);
}

/* EULA — first-run agreement modal + Legal-view "Terms of Use" card.
   `.eula-body` is used both inside `.modal-body` and inside `.legal-card-content`, so it
   carries its own typography (the legal card only styles p/ul/li/strong). */
.eula-modal-content {
    max-width: 760px;
}

.eula-footer {
    /* Decline on the left, Accept on the right — a deliberate, separated choice. */
    justify-content: space-between;
}

.eula-body {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
    line-height: 1.65;
    max-width: var(--measure);
}

.eula-body p {
    margin: 0 0 0.85rem;
}

.eula-body ul {
    margin: 0.5rem 0 1rem;
    padding-left: 1.4rem;
}

.eula-body li {
    margin-bottom: 0.4rem;
}

.eula-body strong {
    color: var(--text-primary);
}

.eula-body a {
    color: var(--accent-primary);
    text-decoration: none;
}

.eula-body a:hover {
    text-decoration: underline;
}

.eula-body h4 {
    margin: 1.4rem 0 0.5rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-primary);
}

.eula-body .eula-lede {
    font-size: 0.95rem;
}

/* Highlighted callout for the Wizards of the Coast / Fan Content notice. */
.eula-body .eula-fanmade {
    padding: 0.85rem 1rem;
    margin: 0.5rem 0 1rem;
    border-left: 3px solid var(--accent-primary);
    border-radius: 8px;
    background-color: var(--bg-tertiary);
}

.eula-body .eula-meta {
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border-color);
    font-size: 0.8rem;
    color: var(--text-tertiary, var(--text-secondary));
}

/* Help Center */
.help-modal-content {
    max-width: 880px;
    width: 100%;
    height: 82vh;
}

.help-toolbar {
    padding: 0.75rem 1.5rem;
    border-bottom: 1px solid var(--border-color);
}

.help-search {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-size: 0.95rem;
}

.help-layout {
    display: flex;
    flex: 1;
    min-height: 0;
}

.help-nav {
    width: 220px;
    flex-shrink: 0;
    border-right: 1px solid var(--border-color);
    overflow-y: auto;
    padding: 0.5rem;
}

.help-nav-item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    text-align: left;
    padding: 0.5rem 0.75rem;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9rem;
}

.help-nav-item:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

.help-nav-item.active {
    background-color: var(--accent-primary);
    color: #fff;
}

/* The flex display above would otherwise defeat the [hidden] attribute used by the filter. */
.help-nav-item[hidden] {
    display: none;
}

.help-nav-item i {
    width: 1.1em;
    text-align: center;
}

.help-content {
    flex: 1;
    overflow-y: auto;
    padding: 1.25rem 1.5rem;
}

.help-topic {
    display: none;
}

.help-topic.active {
    display: block;
    max-width: var(--measure);
}

.help-topic h3 {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0;
    color: var(--text-primary);
}

.help-topic h4 {
    margin: 1.1rem 0 0.35rem;
    color: var(--text-primary);
}

.help-topic p,
.help-topic li {
    color: var(--text-secondary);
    line-height: 1.6;
}

.help-topic ul,
.help-topic ol {
    padding-left: 1.25rem;
    margin: 0.4rem 0;
}

.help-topic kbd {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    border: 1px solid var(--border-color);
    border-bottom-width: 2px;
    border-radius: 5px;
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 0.82em;
    font-family: inherit;
}

.help-topic code {
    padding: 0.05rem 0.35rem;
    border-radius: 5px;
    background-color: var(--bg-tertiary);
    font-size: 0.88em;
}

.help-empty {
    color: var(--text-muted);
    padding: 1rem 0.25rem;
}

@media (max-width: 680px) {
    .help-layout {
        flex-direction: column;
    }

    .help-nav {
        width: auto;
        border-right: none;
        border-bottom: 1px solid var(--border-color);
        display: flex;
        flex-wrap: wrap;
        gap: 0.25rem;
    }

    .help-nav-item {
        width: auto;
    }

    .help-modal-content {
        height: 90vh;
    }
}

/* Modal Tabs */
.modal-tabs {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
    border-bottom: 2px solid var(--border-color);
    padding-bottom: 0.5rem;
}

.modal-tab {
    flex: 1;
    padding: 0.75rem 1rem;
    background: none;
    border: none;
    border-radius: 8px;
    color: var(--text-secondary);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition-interactive);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

.modal-tab:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

.modal-tab.active {
    background-color: var(--accent-primary);
    color: white;
}

.modal-tab-content {
    display: none;
}

.modal-tab-content.active {
    display: block;
}

/* Whole-page drop target (FR-IO-8): shown while a file is dragged over the app. pointer-events
   stays off so the drop lands on the element underneath (a modal's own zone keeps working). */
#file-drop-overlay {
    position: fixed;
    inset: 0;
    z-index: 3000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--bg-primary) 75%, transparent);
    pointer-events: none;
}

#file-drop-overlay[hidden] {
    display: none;
}

.file-drop-overlay-card {
    border: 2px dashed var(--accent-primary);
    border-radius: 12px;
    background: var(--bg-secondary);
    padding: 2rem 3rem;
    text-align: center;
    font-size: 1.1rem;
    color: var(--text-primary);
}

.file-drop-overlay-card i {
    display: block;
    font-size: 3rem;
    color: var(--accent-primary);
    margin-bottom: 0.75rem;
}

/* File Drop Zone */
.file-drop-zone {
    border: 2px dashed var(--border-color);
    border-radius: 12px;
    padding: 2rem;
    text-align: center;
    transition: var(--transition-interactive);
}

.file-drop-zone:hover,
.file-drop-zone.dragover {
    border-color: var(--accent-primary);
    background-color: var(--bg-tertiary);
}

.file-drop-zone i {
    font-size: 3rem;
    color: var(--accent-primary);
    margin-bottom: 1rem;
}

.file-drop-zone p {
    color: var(--text-primary);
    margin: 0.5rem 0;
}

.file-drop-zone span {
    color: var(--text-muted);
    font-size: 0.875rem;
}

.file-drop-zone .file-formats {
    color: var(--text-muted);
    font-size: 0.75rem;
    margin-top: 1rem;
}

.file-input-label {
    margin-top: 1rem;
    cursor: pointer;
}

/* Import Preview */
.import-preview {
    background-color: var(--bg-tertiary);
    border-radius: 12px;
    padding: 1rem;
}

.import-preview-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--border-color);
}

.import-preview-header i {
    color: var(--accent-primary);
    font-size: 1.25rem;
}

.import-preview-header span {
    flex: 1;
    color: var(--text-primary);
    font-weight: 500;
}

/* Sample rows in the collection file-import preview. */
.import-sample {
    margin-top: 0.5rem;
    font-size: 0.85rem;
    line-height: 1.6;
    color: var(--text-secondary);
    max-height: 12rem;
    overflow-y: auto;
}

.import-skipped {
    color: var(--text-tertiary, var(--text-secondary));
}

.import-note {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Textarea styling */
textarea {
    width: 100%;
    padding: 0.75rem 1rem;
    font-size: 0.875rem;
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    border: 2px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    resize: vertical;
    transition: border-color var(--transition-speed);
}

textarea:focus {
    outline: none;
    border-color: var(--accent-primary);
}

textarea::placeholder {
    color: var(--text-muted);
}

/* Utility Classes */
.hidden {
    display: none !important;
}

.visible {
    display: block !important;
}

/* ===========================================
   RTL (Right-to-Left) Support
   =========================================== */

/* Base RTL direction */
[dir='rtl'] {
    text-align: right;
}

/* No flex-direction overrides here, on purpose. A flex row already follows the document
   direction: under dir="rtl" its first child sits on the right. The row-reverse rules that
   used to live here flipped it BACK, so the header actions, section headers, modal headers,
   footer links and deck category headers rendered in LTR order in Arabic — measured on
   2026-09-11 (section-header's title at x=72 in a 1280px viewport, i.e. the left edge). */

/* Flip margins and paddings */
[dir='rtl'] .back-btn {
    margin-right: 0;
    margin-left: 1rem;
}

[dir='rtl'] .back-btn i {
    margin-right: 0;
    margin-left: 0.5rem;
    transform: scaleX(-1);
}

[dir='rtl'] .section-header h2 i,
[dir='rtl'] .card-header i {
    margin-right: 0;
    margin-left: 0.75rem;
}

[dir='rtl'] .menu-item i {
    margin-right: 0;
    margin-left: 0.75rem;
}

[dir='rtl'] .btn i {
    margin-right: 0;
    margin-left: 0.5rem;
}

/* Search input */
[dir='rtl'] .search-input {
    padding-left: 1rem;
    padding-right: 3rem;
    text-align: right;
}

[dir='rtl'] .search-icon {
    left: auto;
    right: 1rem;
}

/* Language selector */
[dir='rtl'] .language-option .lang-flag-icon {
    margin-right: 0;
    margin-left: 0.5rem;
}

/* Modal close button */
[dir='rtl'] .modal-close {
    right: auto;
    left: 1rem;
}

/* Form inputs */
[dir='rtl'] input,
[dir='rtl'] textarea,
[dir='rtl'] select {
    text-align: right;
}

/* Cards grid - keep LTR for visual consistency */
[dir='rtl'] .cards-grid,
[dir='rtl'] .decks-grid,
[dir='rtl'] .collections-grid {
    direction: ltr;
}

[dir='rtl'] .cards-grid > *,
[dir='rtl'] .decks-grid > *,
[dir='rtl'] .collections-grid > * {
    direction: rtl;
}

/* Notifications */
[dir='rtl'] .notification-content {
    margin-left: 0;
    margin-right: 1rem;
}

[dir='rtl'] .notification-badge {
    right: auto;
    left: -4px;
}

/* Arrows and chevrons */
[dir='rtl'] .fa-chevron-right,
[dir='rtl'] .fa-arrow-right,
[dir='rtl'] .fa-angle-right {
    transform: scaleX(-1);
}

[dir='rtl'] .fa-chevron-left,
[dir='rtl'] .fa-arrow-left,
[dir='rtl'] .fa-angle-left {
    transform: scaleX(-1);
}

/* Deck categories */
[dir='rtl'] .deck-category-header i {
    margin-right: 0;
    margin-left: 0.5rem;
}

/* Stats and info items */
[dir='rtl'] .stat-item,
[dir='rtl'] .info-item {
    text-align: right;
}

/* Lists */
[dir='rtl'] ul,
[dir='rtl'] ol {
    padding-right: 1.5rem;
    padding-left: 0;
}

/* Scrollbar position for RTL */
[dir='rtl'] ::-webkit-scrollbar {
    left: 0;
    right: auto;
}

/* ============================================================
   Keyboard focus indicator (accessibility)
   Many controls set `outline: none` on :focus, which leaves
   keyboard users with no visible focus target. Restore a clear
   ring for keyboard navigation only (:focus-visible), so mouse
   clicks stay clean. Placed last so it wins equal-specificity
   :focus rules by source order.
   ============================================================ */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.btn:focus-visible,
.icon-btn:focus-visible,
.btn-icon:focus-visible,
.color-chip:focus-visible,
.printing-chip:focus-visible,
.report-card:focus-visible,
.deck-filter-input:focus-visible,
.collection-card-filter:focus-visible,
.form-group input:focus-visible,
.form-group select:focus-visible,
.filter-group input:focus-visible,
.filter-group select:focus-visible,
.language-option:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

/* Floating toast (brief, non-blocking status messages). */
.app-toast {
    position: fixed;
    left: 50%;
    bottom: 1.5rem;
    transform: translateX(-50%) translateY(1rem);
    max-width: 90vw;
    padding: 0.6rem 1rem;
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    font-size: 0.9rem;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
    opacity: 0;
    pointer-events: none;
    transition:
        opacity var(--transition-speed),
        transform var(--transition-speed);
    z-index: 2000;
}

.app-toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}
/* Signed in, the bottom nav (full-width bar on phones, floating pill on desktop) owns the
   bottom band; the toast used to land on top of it. */
body.has-app-nav .app-toast {
    bottom: 5rem;
}

.app-toast--error {
    border-color: var(--error-color, #dc2626);
    border-left: 4px solid var(--error-color, #dc2626);
}

.app-toast--success {
    border-color: var(--success-color, #16a34a);
    border-left: 4px solid var(--success-color, #16a34a);
}

.app-toast--warning {
    border-color: var(--warning-color, #b07900);
    border-left: 4px solid var(--warning-color, #b07900);
}

/* In-app dialogs (confirm / prompt / choose) — js/ui-dialog.js */
.app-dialog-content {
    max-width: 440px;
    width: 100%;
}

.app-dialog .modal-body p {
    margin: 0;
    color: var(--text-secondary);
    line-height: 1.55;
}

.app-dialog .dlg-label {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    font-size: 0.9rem;
    color: var(--text-secondary);
}

.app-dialog .dlg-input {
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-size: 1rem;
}

.app-dialog .dlg-choices {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.app-dialog .dlg-choice {
    justify-content: flex-start;
    text-align: left;
}

.btn-danger {
    background-color: var(--error-color, #dc2626);
    color: #fff;
    border-color: transparent;
}

.btn-danger:hover {
    filter: brightness(0.92);
}

/* Skeleton loaders (perceived performance while results load) */
.skeleton {
    background: linear-gradient(
        90deg,
        var(--bg-tertiary) 25%,
        var(--border-color) 37%,
        var(--bg-tertiary) 63%
    );
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.3s ease-in-out infinite;
    border-radius: 6px;
}

@keyframes skeleton-shimmer {
    0% {
        background-position: 100% 0;
    }
    100% {
        background-position: -100% 0;
    }
}

.skeleton-card {
    pointer-events: none;
}

.skeleton-art {
    aspect-ratio: 63 / 88;
    width: 100%;
}

.skeleton-line {
    height: 0.8rem;
    margin-top: 0.6rem;
}

.skeleton-line.short {
    width: 60%;
}

@media (prefers-reduced-motion: reduce) {
    .skeleton {
        animation: none;
    }
    /* Blanket reduced-motion guard (NFR-O-10 / WCAG 2.3.3): neutralize all
       animation and transition for users who ask for reduced motion, rather
       than only the handful of named animations. */
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* Visible keyboard focus across the app (WCAG 2.4.7) */
:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Deck autosave status indicator */
.deck-save-status {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-left: 0.75rem;
    transition: opacity var(--transition-speed);
}

.deck-save-status.saving {
    color: var(--text-secondary);
}

.deck-save-status.saved {
    color: var(--success-color, #16a34a);
}

.deck-save-status.saved::before {
    content: '\2713\00a0'; /* check mark + nbsp */
}

/* Onboarding / discoverability hints */
.empty-hint {
    margin-top: 1rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.search-hint {
    margin-top: 0.75rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.search-hint code,
.empty-hint code {
    padding: 0.05rem 0.35rem;
    border-radius: 5px;
    background-color: var(--bg-tertiary);
    font-size: 0.9em;
}

/* Persistent app navigation: full-width bottom tab bar (mobile),
   centered floating pill (desktop) so it never collides with the per-view headers. */
.app-nav {
    position: fixed;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    width: 100%;
    display: flex;
    justify-content: space-around;
    gap: 0.25rem;
    padding: 0.25rem 0.25rem;
    padding-bottom: calc(0.25rem + env(safe-area-inset-bottom, 0px));
    background-color: var(--bg-secondary);
    border-top: 1px solid var(--border-color);
    z-index: 900;
}

.app-nav[hidden] {
    display: none;
}

.app-nav-tab {
    flex: 1;
    min-height: 48px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 0.35rem 0.5rem;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.7rem;
    font-family: inherit;
}

.app-nav-tab i {
    font-size: 1.15rem;
}

.app-nav-tab:hover {
    color: var(--text-primary);
}

.app-nav-tab.active {
    color: var(--accent-primary);
}

body.has-app-nav {
    padding-bottom: 64px;
}

/* The full-viewport-height floor (`.view` / `#app { min-height: 100vh }`) stacks on top of
   the body padding-bottom that clears the fixed bottom nav, so a page ends up `100vh + navHeight`
   tall and gains a dead scroll on short content — and the dashboard's sticky sub-header then
   hides its top tab when that phantom scroll is used. Trim the floor by the nav height, but
   only while the analytics dashboard is shown (`body.dash-active`, toggled by the view) so other
   pages — where the fixed consent banner sits over the reserved bottom space — are untouched. */
body.dash-active.has-app-nav #app,
body.dash-active.has-app-nav #analytics-view {
    min-height: calc(100vh - 64px);
}

@media (min-width: 769px) {
    .app-nav {
        width: auto;
        bottom: 1rem;
        gap: 0.25rem;
        padding: 0.3rem 0.4rem;
        border: 1px solid var(--border-color);
        border-radius: 999px;
        box-shadow: var(--shadow-xl);
    }

    .app-nav-tab {
        flex: 0 0 auto;
        flex-direction: row;
        gap: 0.45rem;
        min-height: 0;
        padding: 0.45rem 1rem;
        border-radius: 999px;
        font-size: 0.85rem;
    }

    .app-nav-tab i {
        font-size: 1rem;
    }

    .app-nav-tab.active {
        background-color: var(--accent-primary);
        color: #fff;
    }

    body.has-app-nav {
        padding-bottom: 76px;
    }

    body.dash-active.has-app-nav #app,
    body.dash-active.has-app-nav #analytics-view {
        min-height: calc(100vh - 76px);
    }
}

/* Mobile: modals become bottom sheets; comfortable touch targets on touch devices. */
@media (max-width: 600px) {
    .modal {
        padding: 0;
        align-items: flex-end;
    }

    .modal-content,
    .app-dialog-content,
    .help-modal-content {
        max-width: 100%;
        width: 100%;
        max-height: 92vh;
        border-radius: 16px 16px 0 0;
    }
}

/* Target size (NFR-O-6). Standalone icon buttons meet 44x44 on EVERY pointer type, not just
   touch: a 24px target is just as hard to hit with a trackpad and a tremor as with a thumb.
   Padding does the work where possible so the glyph itself is not enlarged. */
.btn-icon {
    min-height: 44px;
    min-width: 44px;
}
/* Dense in-row controls (deck stacks, modal close, table row actions) are the documented
   exception: they sit inside rows whose height is set by their content, and forcing 44px there
   pushes tables into horizontal overflow. They meet WCAG 2.2 AA's 24x24 (2.5.8) with spacing,
   not the 44px AAA target this project otherwise holds itself to. */
.icon-btn,
.btn-sm {
    min-height: 32px;
    min-width: 32px;
}

@media (pointer: coarse) {
    /* On touch there is no trackpad precision to fall back on, so the dense controls grow too —
       vertically only, to avoid horizontal overflow on narrow screens. */
    .icon-btn,
    .btn-sm {
        min-height: 40px;
    }
}

/* Users who ask the OS for more contrast get solid borders instead of subtle ones, and
   forced-colors (Windows high contrast) must not be fought with our own colours. */
@media (prefers-contrast: more) {
    :root {
        --border-color: currentColor;
    }
    .btn,
    .report-card,
    .profile-card,
    input,
    select,
    textarea {
        border-width: 2px;
    }
}

@media (forced-colors: active) {
    /* Let the forced palette through; keep only the shapes. */
    .btn,
    .btn-icon,
    .report-card,
    .profile-card {
        border: 1px solid ButtonBorder;
        background-color: ButtonFace;
        color: ButtonText;
        forced-color-adjust: none;
    }
    :focus-visible {
        outline: 2px solid Highlight;
        outline-offset: 2px;
    }
}

/* Search results: grid/table view toggle + table layout */
.view-toggle {
    display: inline-flex;
}

.view-toggle .btn {
    border-radius: 0;
}

.view-toggle .btn:first-child {
    border-top-left-radius: var(--border-radius);
    border-bottom-left-radius: var(--border-radius);
}

.view-toggle .btn:last-child {
    border-top-right-radius: var(--border-radius);
    border-bottom-right-radius: var(--border-radius);
}

.view-toggle .btn.active {
    background-color: var(--accent-primary);
    color: #fff;
}

.results-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-sm);
}

/* The card table runs to 11 columns (NFR-F-1). Below the width where they stop fitting, let it
   scroll sideways inside its own container rather than crushing every column to an unreadable
   few characters. Deliberately scoped to the narrow range: at any width the wrapper would
   become a scroll container in BOTH axes (CSS forces overflow-y to auto once overflow-x is not
   visible), and the table's sticky `thead` would then stick to a wrapper that never scrolls
   vertically instead of to the page — losing the header on every long desktop result set. */
@media (max-width: 900px) {
    .table-scroll {
        overflow-x: auto;
        overscroll-behavior-x: contain;
    }

    .table-scroll .results-table {
        min-width: 760px;
    }
}

.results-table th,
.results-table td {
    padding: var(--space-2) 0.6rem;
    border-bottom: 1px solid var(--border-color);
    text-align: left;
    vertical-align: middle;
}

.results-table thead th {
    color: var(--text-secondary);
    font-weight: 600;
    position: sticky;
    top: 0;
    background-color: var(--bg-secondary);
    z-index: 1;
}

.results-table tbody tr:hover {
    background-color: var(--bg-tertiary);
}

.link-btn {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: var(--accent-primary);
    cursor: pointer;
    text-align: left;
}

.link-btn:hover {
    text-decoration: underline;
}

.results-table .rt-mv,
.results-table .rt-price {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.results-table .rt-price {
    font-weight: 600;
}

.results-table .rt-up {
    color: var(--success-color, #16a34a);
}

.results-table .rt-down {
    color: var(--error-color, #dc2626);
}

.results-table .rt-actions {
    text-align: right;
    white-space: nowrap;
}

.results-table .rt-mana {
    white-space: nowrap;
}

.results-table .rt-mana .mana-symbol {
    font-size: 0.78rem;
}

/* Table footer: page totals (count, avg MV, price sum). */
.results-table tfoot td {
    border-top: 2px solid var(--border-color);
    border-bottom: none;
    color: var(--text-secondary);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    background-color: var(--bg-secondary);
    position: sticky;
    bottom: 0;
}

/* Column chooser (table view) */
.columns-control {
    position: relative;
    display: inline-flex;
}

.columns-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 20;
    min-width: 170px;
    padding: 0.4rem;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
}

.columns-menu-head {
    margin: 0 0 0.3rem;
    padding: 0 0.35rem;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}

.columns-layouts {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    margin: 0 0 0.35rem;
    padding: 0 0.15rem 0.4rem;
    border-bottom: 1px solid var(--border-color);
}

.columns-layouts .layout-select {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 100%;
}

.columns-layouts .btn {
    flex: 0 0 auto;
}

.columns-menu-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.32rem 0.4rem;
    border-radius: 6px;
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--text-primary);
}

.columns-menu-item:hover {
    background-color: var(--bg-tertiary);
}

.columns-menu-item input {
    accent-color: var(--accent-primary);
}

/* Comprehensive Rules browser */
.rules-modal-content {
    max-width: 820px;
    width: 100%;
    height: 82vh;
}

.rules-toolbar {
    margin-bottom: 0.75rem;
}

.rules-search {
    width: 100%;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-size: 1rem;
}

.rules-results {
    overflow-y: auto;
    max-height: calc(82vh - 12rem);
    border: 1px solid var(--border-color);
    border-radius: 8px;
}

.rule-row {
    display: grid;
    grid-template-columns: 5.5rem 1fr;
    gap: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--border-color);
    font-size: 0.9rem;
}

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

.rule-id {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--accent-primary);
}

.rule-text {
    color: var(--text-secondary);
    line-height: 1.5;
}

.rule-text mark {
    background-color: var(--accent-secondary);
    color: #fff;
    border-radius: 3px;
    padding: 0 2px;
}

.rules-foot {
    margin: 0.75rem 0 0;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Guest / demo mode */
.login-demo-btn {
    width: 100%;
    max-width: 400px;
    margin: 1rem auto 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    background: transparent;
    border: 1px solid var(--accent-primary);
    color: var(--accent-primary);
    font-weight: 600;
}

.login-demo-btn:hover {
    background: var(--accent-primary);
    color: #fff;
}

.login-demo-btn .fa-flask {
    font-size: 0.95em;
}

.demo-badge {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 1500;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.35rem 0.35rem 0.35rem 0.85rem;
    background-color: var(--bg-secondary);
    border: 1px solid var(--accent-secondary);
    border-radius: 999px;
    box-shadow: var(--shadow-xl);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-primary);
}

.demo-badge i {
    color: var(--accent-secondary);
}

/* Keep the demo badge clear of the bottom nav: above the full-width tab bar on phones, and
   above the centred desktop pill below ~1500px, where the two used to overlap (the pill is
   ~700px wide and centred; at 1200px the badge sat on its Help tab). */
@media (max-width: 768px) {
    .demo-badge {
        bottom: 72px;
    }
}
@media (min-width: 769px) and (max-width: 1500px) {
    .demo-badge {
        bottom: 4.5rem;
    }
}

/* Draw-probability calculator modal */
.prob-inputs {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.6rem;
    margin-bottom: 0.85rem;
}
.prob-inputs label {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.prob-inputs input {
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.95rem;
}
.prob-result {
    padding: 0.6rem 0.8rem;
    background-color: var(--bg-tertiary);
    border-radius: var(--border-radius);
    color: var(--text-primary);
    margin-bottom: 1rem;
}
.prob-quick {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}
.prob-chip {
    padding: 0.25rem 0.6rem;
    border-radius: 999px;
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Collection card-list group headers */
.card-group-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.85rem 0 0.4rem;
    padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-secondary);
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.card-group-header:first-child {
    margin-top: 0;
}
.card-group-count {
    color: var(--text-muted);
    font-weight: 600;
}

/* Card-detail external lookup links */
.card-detail-lookups {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.85rem;
    font-size: 0.85rem;
}
.card-detail-lookups .lookup-label {
    color: var(--text-secondary);
}
.detail-lookup {
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    border: 1px solid var(--border-color);
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    text-decoration: none;
    transition: var(--transition-interactive);
}
.detail-lookup:hover {
    color: var(--accent-primary);
    border-color: var(--accent-primary);
}

/* Missing Set Cards report */
.missing-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.85rem;
}
.missing-summary {
    color: var(--text-secondary);
    font-size: 0.85rem;
}
.missing-progress {
    margin-bottom: 0.85rem;
}
.ed-bar {
    height: 8px;
    border-radius: 4px;
    background: var(--surface-2, rgba(127, 127, 127, 0.18));
    overflow: hidden;
}
.ed-bar > span {
    display: block;
    height: 100%;
    background: var(--accent, #4caf50);
    border-radius: 4px;
    transition: width 0.3s ease;
}
.missing-list {
    max-height: 60vh;
    overflow-y: auto;
}
.missing-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
.missing-table th,
.missing-table td {
    text-align: left;
    padding: 0.35rem 0.6rem;
    border-bottom: 1px solid var(--border-color);
}
.missing-table th {
    color: var(--text-secondary);
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.missing-table tr.is-missing td {
    color: var(--text-muted);
}
.missing-table td:last-child {
    text-align: center;
}

/* Feature info (i) icons + hover/focus tooltips */
.report-card,
.profile-card {
    position: relative;
}
.modal-header h2 {
    flex: 1 1 auto;
    min-width: 0;
}
.info-icon {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    color: var(--text-muted);
    opacity: 0.6;
    cursor: help;
    z-index: 3;
}
.modal-header .info-icon {
    position: relative;
    top: auto;
    right: auto;
    margin-right: 0.4rem;
    flex: 0 0 auto;
}
.info-icon:hover,
.info-icon:focus-visible {
    opacity: 1;
    color: var(--accent-primary);
    outline: none;
}
.info-icon::after {
    content: attr(data-info);
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    width: max-content;
    max-width: 250px;
    white-space: normal;
    text-align: left;
    font-size: 0.78rem;
    font-weight: 400;
    line-height: 1.4;
    color: var(--text-primary);
    background-color: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    padding: 0.5rem 0.65rem;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.35);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    transition:
        opacity var(--transition-speed),
        transform var(--transition-speed);
    z-index: 100;
    pointer-events: none;
}
.info-icon:hover::after,
.info-icon:focus-visible::after {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

/* Ability icons (v4 artwork; themed via mask + currentColor) */
.ability-icon {
    display: inline-block;
    width: 1.05em;
    height: 1.05em;
    margin-right: 0.4em;
    vertical-align: -0.18em;
    flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

/* Deck Properties form */
/* Collection completion-by-edition report */
.set-completion-content {
    max-width: 560px;
}
.set-completion-body {
    max-height: 60vh;
    overflow-y: auto;
}
.set-completion-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
.set-completion-table th,
.set-completion-table td {
    padding: 0.35rem 0.5rem;
    text-align: left;
    border-bottom: 1px solid var(--border-color, #ddd);
}
.set-completion-table td.sc-count {
    white-space: nowrap;
    color: var(--text-muted, #666);
}
.sc-bar-cell {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 140px;
}
.sc-bar {
    position: relative;
    flex: 1;
    height: 8px;
    border-radius: 4px;
    background: var(--border-color, #e2e2e2);
    overflow: hidden;
}
.sc-bar-fill {
    height: 100%;
    background: var(--accent-color, #4caf50);
    border-radius: 4px;
}
.sc-pct {
    min-width: 2.5rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.deck-props {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.props-field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.props-field > span {
    color: var(--text-secondary);
    font-size: 0.85rem;
}
.props-field input,
.props-field select,
.props-field textarea {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font: inherit;
}
.props-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.props-note {
    color: var(--text-secondary);
    font-size: 0.85rem;
}

/* Deck Properties: public page toggle (FR-ACCT-9) */
.props-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-primary);
}
.props-check input {
    width: 1rem;
    height: 1rem;
    padding: 0;
}
.props-public .hand-note {
    margin: 0;
}
.props-public-link {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border: 1px dashed var(--border-color);
    border-radius: var(--border-radius);
    background: var(--bg-tertiary);
}
.props-public-link[hidden] {
    display: none;
}
.props-public-url {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
    font-family: ui-monospace, Consolas, monospace;
    font-size: 0.85rem;
}
.deck-public-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-top: 0.5rem;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    background: var(--accent-fill);
    color: var(--text-on-accent, #fff);
    font-size: 0.75rem;
}

/* Public deck page (FR-ACCT-9): read-only, prose-like layout */
.pdx-deck {
    max-width: 760px;
    margin: 0 auto;
}
.pdx-head {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
}
.pdx-title {
    margin: 0;
    font-size: 1.75rem;
}
.pdx-colors {
    display: flex;
    gap: 0.25rem;
}
.pdx-meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.25rem 1rem;
    margin: 0;
    font-size: 0.9rem;
}
.pdx-meta dt {
    color: var(--text-secondary);
}
.pdx-meta dd {
    margin: 0;
}
.pdx-desc {
    white-space: pre-wrap;
    color: var(--text-primary);
}
.pdx-board {
    margin-top: 1.25rem;
}
.pdx-board h3 {
    margin: 0 0 0.5rem;
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 0.35rem;
}
.pdx-board h4 {
    margin: 0.75rem 0 0.25rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.pdx-cards {
    list-style: none;
    margin: 0;
    padding: 0;
    columns: 2 18rem;
}
.pdx-cards li {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.15rem 0;
    break-inside: avoid;
}
.pdx-qty {
    min-width: 1.5rem;
    color: var(--text-secondary);
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.pdx-name {
    flex: 0 1 auto;
}
.pdx-open {
    margin-top: 0.75rem;
}
.pdx-cost {
    display: inline-flex;
    gap: 0.1rem;
}
.pdx-foot {
    margin-top: 2rem;
    text-align: center;
}
.props-computed {
    border-top: 1px solid var(--border-color);
    padding-top: 0.6rem;
}

/* Settings / Options (font-size scales rem-based UI; default medium) */
html.fs-small {
    font-size: 87.5%;
}
html.fs-large {
    font-size: 112.5%;
}
.settings-body {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}
.settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
.settings-label {
    color: var(--text-secondary);
}
.settings-row select,
.settings-row input {
    padding: 0.35rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-primary);
    color: var(--text-primary);
}
.settings-max-same {
    width: 5rem;
}

/* Double-faced card flip (card detail) */
.card-art-wrap {
    position: relative;
    display: inline-block;
}
.card-flip-btn {
    position: absolute;
    bottom: 10px;
    right: 10px;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: #fff;
    background-color: rgba(0, 0, 0, 0.65);
    border: 1px solid rgba(255, 255, 255, 0.35);
    border-radius: 999px;
    cursor: pointer;
    transition: background-color var(--transition-speed);
}
.card-flip-btn:hover {
    background-color: var(--accent-primary);
}
.card-detail-face {
    margin-top: 0.35rem;
    text-align: center;
    font-size: 0.85rem;
    color: var(--text-secondary);
}

/* Per-card legality (card detail) */
.legality-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: 0.35rem 0.75rem;
}
.legality-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.2rem 0;
}
.legality-format {
    color: var(--text-secondary);
    font-size: 0.9rem;
}
.legality-pill {
    flex-shrink: 0;
    font-size: var(--font-size-2xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 0.12rem var(--space-2);
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
}
/* `.legality-legal` / `-restricted` / `-notlegal` are coloured with the results-grid chips,
   next to `.card-legal-chip` — one definition for both surfaces. */

/* Deck Legality modal — per-format issue list */
.legality-table td {
    vertical-align: top;
}
.legality-issues {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.85rem;
    line-height: 1.45;
}
.legality-issue {
    margin: 0.05rem 0;
}
.legality-issue-banned {
    color: var(--danger-color);
    font-weight: 600;
}
.legality-issue-restricted {
    color: var(--warning-color);
}
.legality-issue-not-in-pool {
    color: var(--text-muted);
}
.legality-caveat {
    margin-top: 0.6rem;
    font-size: 0.78rem;
}

/* Browse Sets report */
.browse-sets-filter {
    flex: 1 1 12rem;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-size: 0.9rem;
}
.browse-sets-list {
    max-height: 60vh;
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.4rem;
}
.browse-set-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.9rem;
    text-align: left;
    cursor: pointer;
    transition: var(--transition-interactive);
}
.browse-set-row:hover {
    border-color: var(--accent-primary);
    color: var(--accent-primary);
}
.browse-set-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.browse-set-count {
    flex-shrink: 0;
    color: var(--text-secondary);
    font-size: 0.8rem;
    background-color: var(--bg-tertiary);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
}

/* Ability browser — collapsible type tree (overrides the grid layout of .browse-sets-list) */
.ab-list.browse-sets-list {
    display: block;
}
.ability-tree {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.ability-group-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    cursor: pointer;
    text-align: left;
    text-transform: capitalize;
    font-weight: 600;
}
.ability-group-header:hover {
    border-color: var(--accent-primary);
}
.ability-group-name {
    flex: 1;
}
.ability-caret {
    font-size: 0.7rem;
    color: var(--text-secondary);
    transition: transform 0.15s ease;
    transform: rotate(90deg);
}
.ability-group.collapsed .ability-caret {
    transform: rotate(0deg);
}
.ability-group-items {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.4rem;
    padding: 0.4rem 0 0.4rem 1.1rem;
}
.ability-group.collapsed .ability-group-items {
    display: none;
}

/* Combos from Collection report */
.combos-list {
    max-height: 60vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.combo-item {
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-secondary);
}
.combo-item-cards {
    font-weight: 600;
    color: var(--text-primary);
}
.combo-plus {
    color: var(--accent-primary);
    margin: 0 0.15rem;
}
.combo-item-desc {
    margin-top: 0.3rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
    line-height: 1.35;
}

/* Batch-update selection (collection detail) */
.collection-card-row.selected {
    border-color: var(--accent-primary);
    box-shadow: inset 0 0 0 1px var(--accent-primary);
}
.card-row-select {
    width: 16px;
    height: 16px;
    cursor: pointer;
}
.collection-batch-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    padding: 0.5rem 0.75rem;
    background-color: var(--bg-tertiary);
    border: 1px solid var(--accent-primary);
    border-radius: var(--border-radius);
}
.collection-batch-bar .batch-count {
    font-weight: 600;
    color: var(--text-primary);
    margin-right: 0.25rem;
}
.collection-batch-bar .batch-qty {
    width: 4rem;
    padding: 0.3rem 0.4rem;
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    background-color: var(--bg-secondary);
    color: var(--text-primary);
}

/* Deck Strategy + Advisor tool layouts */
.strategy-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 0.6rem;
}
.strategy-row {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.6rem 0.7rem;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
}
.strategy-row strong {
    color: var(--text-primary);
    font-size: 1.05rem;
}
.advisor-list {
    margin: 0;
    padding-left: 1.1rem;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    color: var(--text-secondary);
    line-height: 1.4;
}

/* ============================================================
   Playtest workspace (full-screen overlay) — roadmap §11
   ============================================================ */
body.pt-open {
    overflow: hidden;
}
.pt-view {
    position: fixed;
    inset: 0;
    z-index: 4000;
    display: none;
    flex-direction: column;
    background: var(--bg-primary);
    color: var(--text-primary);
}
/* The playtest board (.pt-view) is a fixed full-screen layer at z-index 4000, so the shared
   modal/dialog layers (.modal, .app-dialog — normally z-index 1000) would render BEHIND it and
   a mouse click's hit-test would land on the board instead of the dialog. Lift them above the
   board WHILE A PLAYTEST IS OPEN (body.pt-open, set in js/playtest.js), staying below the
   playtest context menu (6000) / hover previews (6500/9999). Scoped to .pt-open so the normal
   app-wide modal/toast stacking (toast is z-index 2000) is unchanged everywhere else. */
body.pt-open .modal,
body.pt-open .app-dialog {
    z-index: 5000;
}
.pt-muted {
    color: var(--text-muted);
}
.pt-muted {
    color: var(--text-muted);
}

/* Top bar */
.pt-topbar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.4rem 0.75rem;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
    flex: 0 0 auto;
}
.pt-topbar-left,
.pt-topbar-right {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}
.pt-topbar-right {
    margin-left: auto;
}
.pt-title {
    font-weight: 700;
}
.pt-steps {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-width: 0;
}
.pt-steps-mid {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    min-width: 0;
}
.pt-turn {
    font-size: 0.8rem;
    color: var(--text-secondary);
    font-weight: 600;
}
.pt-step-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem;
    justify-content: center;
}
.pt-step-pill {
    font-size: 0.68rem;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    cursor: pointer;
    white-space: nowrap;
    border: 1px solid transparent;
}
.pt-step-pill:hover {
    border-color: var(--border-color);
}
.pt-step-pill.active {
    background: var(--accent-primary);
    color: #fff;
}

/* Body + log */
.pt-body {
    flex: 1 1 auto;
    display: flex;
    min-height: 0;
}
.pt-stage {
    flex: 1 1 auto;
    overflow: auto;
    padding: 0.5rem;
}
.pt-log {
    flex: 0 0 280px;
    border-left: 1px solid var(--border-color);
    background: var(--bg-secondary);
    display: flex;
    flex-direction: column;
    min-height: 0;
}
.pt-log-head {
    padding: 0.5rem 0.75rem;
    font-weight: 700;
    border-bottom: 1px solid var(--border-color);
}
.pt-log-list {
    overflow: auto;
    padding: 0.5rem 0.75rem;
    font-size: 0.8rem;
    line-height: 1.5;
}
.pt-log-row {
    padding: 0.1rem 0;
}
.pt-log-sba {
    color: var(--accent-secondary);
}

/* Setup screen */
.pt-setup {
    max-width: 520px;
    margin: 2rem auto;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
}
.pt-field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.85rem;
    flex: 1;
}
.pt-field > span {
    color: var(--text-secondary);
    font-weight: 600;
}
.pt-field input,
.pt-field select,
.pt-field textarea {
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--bg-primary);
    color: var(--text-primary);
    font: inherit;
}
.pt-field-row {
    display: flex;
    gap: 0.6rem;
}
.pt-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
}
.pt-setup-actions {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.4rem;
}

/* Table + seats */
.pt-table {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    position: relative;
    min-height: 100%;
}
.pt-seat {
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-secondary);
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.pt-seat-active {
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 1px var(--accent-primary) inset;
}
.pt-seat-lost {
    opacity: 0.6;
}
.pt-seat-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    font-size: 0.82rem;
}
.pt-seat-name {
    font-weight: 700;
}
.pt-life-ctl,
.pt-poison,
.pt-mana-pool,
.pt-piles {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
}
.pt-life {
    min-width: 1.6rem;
    text-align: center;
    font-weight: 700;
    font-size: 1rem;
}
.pt-mana {
    border: 1px solid var(--border-color);
    border-radius: 5px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    padding: 0.05rem 0.3rem;
    font-size: 0.72rem;
    cursor: pointer;
}
.pt-mana b {
    margin-left: 0.15rem;
}
.pt-mana-w {
    border-bottom: 2px solid #f8e7b9;
}
.pt-mana-u {
    border-bottom: 2px solid #aae0fa;
}
.pt-mana-b {
    border-bottom: 2px solid #bab1ab;
}
.pt-mana-r {
    border-bottom: 2px solid #f9aa8f;
}
.pt-mana-g {
    border-bottom: 2px solid #9bd3ae;
}
.pt-pile {
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    padding: 0.2rem 0.5rem;
    font-size: 0.75rem;
    cursor: pointer;
}
.pt-pile:hover {
    border-color: var(--accent-primary);
}

/* Battlefield + hand rows */
.pt-battlefield {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-height: 4.5rem;
    background: var(--bg-primary);
    border-radius: 8px;
    padding: 0.35rem;
}
.pt-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    min-height: 4.6rem;
    align-content: flex-start;
}
.pt-hand {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    min-height: 4.6rem;
    border-top: 1px dashed var(--border-color);
    padding-top: 0.35rem;
}
.pt-empty {
    color: var(--text-muted);
    font-size: 0.75rem;
    align-self: center;
}

/* Cards */
.pt-card {
    position: relative;
    width: 86px;
    height: 64px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--bg-tertiary);
    background-size: cover;
    background-position: center 18%;
    cursor: pointer;
    overflow: hidden;
    user-select: none;
    transition: transform 0.12s ease;
}
.pt-card-bf {
    width: 92px;
}
.pt-card:hover {
    transform: translateY(-2px);
    border-color: var(--accent-primary);
    z-index: 2;
}
.pt-card-face {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.2rem 0.3rem;
    height: 100%;
}
.pt-has-img .pt-card-face {
    background: linear-gradient(to top, rgba(0, 0, 0, 0.78) 30%, rgba(0, 0, 0, 0) 70%);
    justify-content: flex-end;
    color: #fff;
}
.pt-card-name {
    font-size: 0.66rem;
    font-weight: 600;
    line-height: 1.1;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.pt-card-cost {
    font-size: 0.6rem;
}
.pt-card-type {
    font-size: 0.55rem;
    color: var(--text-muted);
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.pt-has-img .pt-card-type {
    color: #ddd;
}
.pt-tapped {
    transform: rotate(12deg);
}
.pt-tapped:hover {
    transform: rotate(12deg) translateY(-2px);
}
.pt-phased {
    opacity: 0.4;
    filter: grayscale(1);
}
.pt-sick::after {
    content: '💤';
    position: absolute;
    top: 1px;
    right: 2px;
    font-size: 0.6rem;
}
.pt-facedown {
    background: repeating-linear-gradient(
        45deg,
        var(--bg-tertiary),
        var(--bg-tertiary) 6px,
        var(--bg-secondary) 6px,
        var(--bg-secondary) 12px
    );
}
.pt-token {
    border-style: dashed;
}
.pt-pt {
    position: absolute;
    bottom: 1px;
    right: 2px;
    font-size: 0.62rem;
    font-weight: 700;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    padding: 0 0.2rem;
    border-radius: 3px;
}
.pt-dmg {
    color: #ff9c8f;
}
.pt-counters {
    position: absolute;
    top: 1px;
    left: 2px;
    display: flex;
    flex-wrap: wrap;
    gap: 1px;
}
.pt-counter {
    font-size: 0.52rem;
    background: var(--accent-secondary);
    color: #fff;
    padding: 0 0.18rem;
    border-radius: 3px;
}
.pt-attached {
    position: absolute;
    bottom: 1px;
    left: 2px;
    font-size: 0.55rem;
}

/* Stack */
.pt-stackzone {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 220px;
    background: var(--bg-secondary);
    border: 2px solid var(--accent-primary);
    border-radius: 10px;
    padding: 0.5rem;
    box-shadow: var(--shadow-lg);
    z-index: 5;
}
.pt-stackzone-empty {
    opacity: 0.4;
    border-style: dashed;
    border-color: var(--border-color);
}
.pt-stack-head {
    font-weight: 700;
    margin-bottom: 0.3rem;
}
.pt-stack-item {
    display: flex;
    justify-content: space-between;
    gap: 0.4rem;
    font-size: 0.78rem;
    padding: 0.2rem 0.3rem;
    border-radius: 5px;
    background: var(--bg-tertiary);
    margin-bottom: 0.2rem;
}
.pt-stack-actions {
    display: flex;
    gap: 0.3rem;
    margin-top: 0.3rem;
}

/* Context menu */
.pt-menu {
    position: fixed;
    z-index: 6000;
    min-width: 190px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    box-shadow: var(--shadow-lg);
    padding: 0.25rem;
    display: flex;
    flex-direction: column;
}
.pt-menu-item {
    text-align: left;
    background: none;
    border: none;
    color: var(--text-primary);
    padding: 0.35rem 0.5rem;
    border-radius: 5px;
    cursor: pointer;
    font: inherit;
    font-size: 0.82rem;
}
.pt-menu-item:hover {
    background: var(--accent-primary);
    color: #fff;
}
.pt-menu-sep {
    height: 1px;
    background: var(--border-color);
    margin: 0.2rem 0;
}

/* Dialogs (counters / tokens / zone browser) */
.pt-dialog .modal-content {
    max-width: 560px;
}
.pt-presets {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}
.pt-counter-rows {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin: 0.5rem 0;
}
.pt-counter-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.pt-counter-row span {
    flex: 1;
}
.pt-cval {
    min-width: 1.5rem;
    text-align: center;
}
.pt-zone-tools {
    display: flex;
    gap: 0.4rem;
    margin-bottom: 0.5rem;
    flex-wrap: wrap;
}
.pt-zlist,
.pt-scry {
    max-height: 48vh;
    overflow: auto;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.pt-zrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.25rem 0.4rem;
    border-radius: 5px;
    background: var(--bg-tertiary);
}
.pt-zacts {
    display: flex;
    gap: 0.2rem;
}
.btn-xs {
    font-size: 0.7rem;
    padding: 0.1rem 0.35rem;
}

/* Combat bar + move banner */
.pt-combat-bar {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
    padding: 0.4rem 0.7rem;
    background: var(--bg-secondary);
    border: 1px solid var(--accent-primary);
    border-radius: 8px;
}
.pt-move-banner {
    position: sticky;
    top: 0;
    z-index: 6;
    margin-bottom: 0.4rem;
    padding: 0.4rem 0.7rem;
    background: var(--accent-secondary);
    color: #fff;
    border-radius: 8px;
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

/* Status badges on cards */
.pt-status {
    position: absolute;
    top: 1px;
    right: 2px;
    display: flex;
    flex-wrap: wrap;
    gap: 1px;
    max-width: 80%;
    justify-content: flex-end;
}
.pt-badge {
    font-size: 0.55rem;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    border-radius: 3px;
    padding: 0 0.15rem;
    line-height: 1.3;
}
.pt-badge.pt-kw {
    background: var(--accent-primary);
}
.pt-badge.pt-cmd {
    background: #c79a3a;
}
.pt-attacking {
    box-shadow: 0 0 0 2px #e0563f inset;
}
.pt-blocking {
    box-shadow: 0 0 0 2px #4a90d9 inset;
}
.pt-groupcount {
    position: absolute;
    bottom: 1px;
    left: 2px;
    font-size: 0.62rem;
    font-weight: 700;
    background: var(--accent-primary);
    color: #fff;
    border-radius: 3px;
    padding: 0 0.2rem;
}
.pt-cmddmg {
    font-size: 0.78rem;
    font-weight: 700;
    color: #e0563f;
}
.pt-collapse {
    font-size: 0.85rem;
}
.pt-seat-collapsed .pt-battlefield,
.pt-seat-collapsed .pt-hand {
    display: none;
}
.pt-kw-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.2rem 0.8rem;
    margin: 0.5rem 0;
}

/* Hover preview */
.pt-preview {
    position: fixed;
    z-index: 6500;
    width: 244px;
    pointer-events: none;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    display: none;
}
.pt-preview img {
    width: 100%;
    display: block;
    border-radius: 10px;
}
.pt-preview-name {
    padding: 0.5rem;
    font-weight: 600;
}

@media (max-width: 720px) {
    .pt-card {
        width: 70px;
        height: 56px;
    }
    .pt-log {
        flex-basis: 200px;
    }
    .pt-stackzone {
        width: 170px;
    }
}

/* ===================================================================
   Public landing page (visitors) — Home / Download / Screenshots
   =================================================================== */
#landing-view {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Header / top nav */
.landing-header {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    /* Extra right padding clears the fixed theme-toggle (48px + 1rem, top-right). */
    padding: 0.75rem 4.75rem 0.75rem 1.5rem;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
    box-shadow: var(--shadow-sm);
}
.landing-brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-family: 'Aclonica', sans-serif;
    font-size: 1.25rem;
    color: var(--text-primary);
    text-decoration: none;
    white-space: nowrap;
}
.landing-brand i {
    color: var(--accent-primary);
}
.landing-tabs {
    display: flex;
    gap: 0.25rem;
    margin-inline: auto;
}
.landing-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    border-radius: 8px;
    color: var(--text-secondary);
    text-decoration: none;
    font-weight: 600;
    border-bottom: 2px solid transparent;
    transition:
        color var(--transition-speed),
        background-color var(--transition-speed);
}
.landing-tab:hover {
    color: var(--text-primary);
    background: var(--bg-tertiary);
}
.landing-tab.is-active {
    color: var(--accent-primary);
    border-bottom-color: var(--accent-primary);
}
.landing-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}
.btn.btn-lg {
    padding: 0.7rem 1.4rem;
    font-size: 1.05rem;
}
/* Anchor-styled buttons on the landing/admin chrome must not inherit the link underline,
   the full-width `.btn-primary` sizing (meant for the auth forms), or the `.btn-secondary`
   left-aligned label — size them to their content and centre the label. */
.landing-header .btn,
.landing-hero-cta .btn,
.admin-header .btn {
    width: auto;
    text-decoration: none;
    justify-content: center;
}

/* Main + panes */
.landing-main {
    flex: 1;
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    padding: 2rem 1.5rem 3rem;
}
.landing-pane[hidden] {
    display: none;
}
.landing-pane-title {
    font-family: 'Aclonica', sans-serif;
    font-size: 2rem;
    margin-bottom: 1rem;
    color: var(--text-primary);
}
.landing-lead {
    font-size: 1.1rem;
    color: var(--text-secondary);
    max-width: 70ch;
    margin-bottom: 1.5rem;
}
.landing-note {
    color: var(--text-secondary);
    margin: 1rem 0 1.5rem;
}

/* Hero */
.landing-hero {
    text-align: center;
    padding: 2.5rem 1rem 2rem;
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--accent-primary) 14%, var(--bg-secondary)),
        var(--bg-secondary)
    );
    border: 1px solid var(--border-color);
    border-radius: 18px;
    box-shadow: var(--shadow-md);
}
.landing-hero-title {
    font-family: 'Aclonica', sans-serif;
    font-size: clamp(1.8rem, 4vw, 2.8rem);
    line-height: 1.15;
    color: var(--text-primary);
    margin-bottom: 0.75rem;
}
.landing-hero-tagline {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--accent-primary);
    margin-bottom: 0.5rem;
}
.landing-hero-lead {
    font-size: 1.1rem;
    color: var(--text-secondary);
    max-width: 60ch;
    margin: 0 auto 1.5rem;
}
.landing-hero-cta {
    display: flex;
    gap: 0.75rem;
    justify-content: center;
    flex-wrap: wrap;
}
.landing-version {
    margin-top: 1rem;
    color: var(--text-secondary);
    font-size: 0.95rem;
}

/* Player personas */
.landing-personas {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin: 2rem 0;
}
.landing-persona {
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}
.landing-persona img {
    width: 100%;
    height: 220px;
    object-fit: cover;
    display: block;
}
.landing-persona figcaption {
    padding: 0.75rem 1rem;
    color: var(--text-secondary);
    font-size: 0.95rem;
    text-align: center;
}

/* Feature cards */
.landing-features {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.25rem;
    margin: 2rem 0;
}
.landing-feature-card,
.landing-callout {
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    padding: 1.5rem;
    box-shadow: var(--shadow-sm);
}
.landing-callout {
    margin: 1.5rem 0;
}
.landing-feature-card h2,
.landing-callout h2 {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 1.3rem;
    margin-bottom: 1rem;
    color: var(--text-primary);
}
.landing-feature-card h2 i,
.landing-callout h2 i {
    color: var(--accent-primary);
}
.landing-feature-card ul,
.landing-callout ul {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.landing-feature-card li,
.landing-callout li {
    position: relative;
    padding-left: 1.4rem;
    color: var(--text-secondary);
    line-height: 1.5;
}
.landing-feature-card li::before,
.landing-callout li::before {
    content: '\f00c';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    position: absolute;
    left: 0;
    top: 0.15rem;
    font-size: 0.8rem;
    color: var(--success-color);
}
.landing-feature-card a,
.landing-callout a,
.landing-lead a {
    color: var(--accent-primary);
    font-weight: 600;
}

/* Downloads */
.landing-downloads {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1rem;
    margin: 1.5rem 0;
}
.landing-download-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.25rem 1.5rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 14px;
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    transition:
        transform var(--transition-speed),
        box-shadow var(--transition-speed),
        border-color var(--transition-speed);
}
.landing-download-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--accent-primary);
}
.landing-download-card .dl-icon {
    font-size: 1.8rem;
    color: var(--accent-primary);
}
.landing-download-card .dl-body {
    display: flex;
    flex-direction: column;
}
.landing-download-card .dl-title {
    font-weight: 700;
    color: var(--text-primary);
}
.landing-download-card .dl-meta {
    font-size: 0.9rem;
    color: var(--text-secondary);
}
.landing-box-shot {
    text-align: center;
    margin: 2rem 0;
}
.landing-box-shot img {
    max-width: 320px;
    width: 100%;
    height: auto;
}

/* Screenshot carousel */
.landing-carousel {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.5rem;
}
.carousel-stage {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--border-color);
    border-radius: 14px;
    background: var(--bg-secondary);
    box-shadow: var(--shadow-md);
}
.carousel-slide {
    display: none;
}
.carousel-slide.is-active {
    display: block;
}
.carousel-slide img {
    width: 100%;
    height: auto;
    display: block;
    background: var(--bg-tertiary);
}
.carousel-slide figcaption {
    padding: 1rem 1.25rem;
    color: var(--text-secondary);
    border-top: 1px solid var(--border-color);
    line-height: 1.5;
}
.carousel-nav {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--accent-primary);
    font-size: 2rem;
    padding: 0.25rem;
    line-height: 1;
    transition:
        transform var(--transition-speed),
        color var(--transition-speed);
}
.carousel-nav:hover {
    color: var(--accent-primary-hover);
    transform: scale(1.1);
}
.carousel-dots {
    grid-column: 2;
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    margin-top: 0.85rem;
}
.carousel-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: none;
    background: var(--border-color);
    cursor: pointer;
    padding: 0;
    transition: background-color var(--transition-speed);
}
.carousel-dot.is-active {
    background: var(--accent-primary);
}

/* Responsive */
@media (max-width: 760px) {
    .landing-header {
        flex-wrap: wrap;
        gap: 0.75rem;
    }
    /* The header's action row (flag, Sign in, Download FREE) does not fit beside the brand at
       phone widths and ran flush off the right edge. Let it wrap, and drop the header's
       Download FREE there: the hero repeats it three lines below. */
    .landing-actions {
        flex-wrap: wrap;
    }
    .landing-actions .btn-primary {
        display: none;
    }
    /* "Try the demo - no account needed" at btn-lg size is wider than the hero card on a
       phone; let the label wrap instead of overflowing the card on both sides. */
    .landing-hero-cta .btn {
        max-width: 100%;
        white-space: normal;
    }
    .landing-tabs {
        order: 3;
        width: 100%;
        margin-inline: 0;
        justify-content: center;
    }
    /* Icon-only tabs at this width — but the label has to stay in the accessibility tree.
       `display: none` removed it outright, leaving three links whose only content was a
       decorative Font Awesome glyph: no accessible name at all (WCAG 2.4.4 / 4.1.2), which a
       Lighthouse mobile run caught and the desktop-width axe sweep structurally cannot.
       Visually hidden instead, so the name stays translated in all 36 locales for free. */
    .landing-tab span {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
    .landing-personas {
        grid-template-columns: 1fr;
    }
    .landing-persona img {
        height: 200px;
    }
    .carousel-nav {
        font-size: 1.5rem;
    }
}

/* ===================================================================
   Admin pages (Tools, Import Card)
   =================================================================== */
.admin-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.85rem 1.5rem;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
    box-shadow: var(--shadow-sm);
    position: sticky;
    top: 0;
    z-index: 20;
}
.admin-header .admin-header-title {
    font-size: 1.3rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-primary);
}
.admin-header .admin-header-title i {
    color: var(--accent-primary);
}
.admin-back {
    text-decoration: none;
}
.admin-main {
    max-width: 1100px;
    margin: 0 auto;
    padding: 1.5rem;
}

/* Tools — link cards */
.admin-tools-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.25rem;
}
.admin-link-list {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.admin-link-list a {
    color: var(--accent-primary);
    text-decoration: none;
}
.admin-link-list a:hover {
    text-decoration: underline;
}

/* ============================================================================
   Analytics Dashboard (admin) — js/analytics-dashboard.js
   ============================================================================ */
.dash-header {
    flex-wrap: wrap;
    /* Reserve room for the fixed top-right theme toggle (48px + 1rem inset) so the toolbar's
       last control (the "To" date picker) isn't hidden under it. */
    padding-right: 5rem;
}
.dash-toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-left: auto;
}
.dash-presets {
    display: inline-flex;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
}
.dash-preset {
    padding: 0.35rem 0.7rem;
    border: none;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    border-right: 1px solid var(--border-color);
}
.dash-preset:last-child {
    border-right: none;
}
.dash-preset:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}
.dash-preset.active {
    background: var(--accent-primary);
    color: #fff;
}
.dash-date {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.dash-date input {
    padding: 0.3rem 0.4rem;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    color-scheme: light dark;
}
.dash-main {
    max-width: 1240px;
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
}
.dash-tabs {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    position: sticky;
    /* Clear the sticky .dash-header (~90px) so the first tab isn't hidden beneath it on scroll. */
    top: 6rem;
}
.dash-tab {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 0.75rem;
    border: none;
    border-left: 3px solid transparent;
    border-radius: 6px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 0.9rem;
    text-align: left;
    width: 100%;
}
.dash-tab i {
    width: 1.1rem;
    text-align: center;
    color: var(--text-muted);
}
.dash-tab:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}
.dash-tab.active {
    background: var(--bg-tertiary);
    color: var(--accent-primary);
    border-left-color: var(--accent-primary);
    font-weight: 600;
}
.dash-tab.active i {
    color: var(--accent-primary);
}

.dash-panel {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    min-height: 240px;
}

/* States */
.dash-loading,
.dash-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 3rem 1rem;
    color: var(--text-secondary);
    text-align: center;
}
.dash-empty i {
    font-size: 2rem;
    color: var(--text-muted);
}
.dash-empty-title {
    font-weight: 600;
    color: var(--text-primary);
}
.dash-empty-body {
    max-width: 46ch;
    font-size: 0.9rem;
}

/* KPI cards */
.kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1rem;
}
.kpi-grid-live {
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.kpi-card {
    position: relative; /* anchor the top-right (i) info icon */
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 1rem 1.1rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    box-shadow: var(--shadow-sm);
}
/* Keep the KPI label clear of the (i) icon top-right. */
.kpi-card > .kpi-label {
    padding-right: 1.25rem;
}
.kpi-label {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-secondary);
}
.kpi-value {
    font-size: 1.7rem;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}
.kpi-foot {
    font-size: 0.8rem;
    color: var(--text-muted);
}
.dash-delta {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.dash-delta.is-up {
    color: var(--success-color);
}
.dash-delta.is-down {
    color: var(--error-color);
}
.dash-delta.is-flat {
    color: var(--text-muted);
}

/* Cards + section layout */
.dash-card {
    position: relative; /* anchor the top-right (i) info icon */
    padding: 1.1rem 1.25rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    box-shadow: var(--shadow-sm);
}
/* Keep the panel title clear of the (i) icon in the top-right corner. */
.dash-card > .dash-card-title {
    padding-right: 1.5rem;
}
/* The home cards' faint 0.6-opacity grey (i) is nearly invisible on the dark analytics
   panels — make the panel + KPI icons clearly legible at rest (hover still highlights to accent). */
.dash-card > .info-icon,
.kpi-card > .info-icon {
    opacity: 1;
    color: var(--text-secondary);
    font-size: 0.95rem;
}
.dash-card-title {
    font-size: 0.95rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
    color: var(--text-primary);
}
.dash-card-title i {
    color: var(--accent-primary);
}
.dash-grid-2 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.25rem;
}

/* Bar lists */
.dash-bars {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}
.dash-bar-row {
    display: grid;
    grid-template-columns: minmax(6rem, 10rem) 1fr auto;
    align-items: center;
    gap: 0.6rem;
}
.dash-bar-label {
    font-size: 0.85rem;
    color: var(--text-primary);
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dash-bar-sub {
    font-size: 0.72rem;
    color: var(--text-muted);
}
.dash-bar-track {
    height: 10px;
    background: var(--bg-tertiary);
    border-radius: 6px;
    overflow: hidden;
}
.dash-bar-fill {
    display: block;
    height: 100%;
    border-radius: 6px;
    background: var(--accent-primary);
}
.dash-bar-val {
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    min-width: 3rem;
    text-align: right;
}

/* SVG charts */
.dash-svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}
.dash-axis {
    display: flex;
    justify-content: space-between;
    margin-top: 0.35rem;
    font-size: 0.72rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.dash-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    margin-top: 0.75rem;
}
.dash-legend-col {
    flex-direction: column;
    gap: 0.4rem;
}
.dash-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.dash-legend-swatch {
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 3px;
    flex: 0 0 auto;
}

/* Donut */
.dash-donut-wrap {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
}
.dash-donut {
    width: 160px;
    height: 160px;
    flex: 0 0 auto;
}
.dash-donut-total {
    font-size: 1.4rem;
    font-weight: 700;
    fill: var(--text-primary);
}
.dash-donut-sub {
    font-size: 0.7rem;
    fill: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Tables + heatmap */
.dash-table-wrap {
    overflow-x: auto;
}
.dash-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
}
.dash-table th {
    text-align: left;
    padding: 0.4rem 0.6rem;
    color: var(--text-secondary);
    font-weight: 600;
    border-bottom: 1px solid var(--border-color);
    white-space: nowrap;
}
.dash-table td {
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-primary);
}
.dash-td-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.dash-td-country {
    white-space: nowrap;
}
.dash-td-path {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8rem;
    word-break: break-all;
}
.settings-optional {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.85em;
}
.dash-td-bar {
    width: 40%;
    min-width: 120px;
}
.dash-heatmap td,
.dash-heatmap th {
    text-align: center;
    border: 1px solid var(--bg-primary);
}
.dash-heatmap td:first-child,
.dash-heatmap th:first-child {
    text-align: left;
}
.dash-heat {
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    color: var(--text-primary);
}
.dash-heat.is-strong {
    color: #fff;
}
.dash-heat-empty {
    background: transparent;
}

/* World-map choropleth (Geography tab) */
.dash-worldmap {
    width: 100%;
}
.dash-map-svg {
    display: block;
    width: 100%;
    height: auto;
    max-height: 60vh;
    background: var(--bg-primary);
    border-radius: 8px;
}
.dash-map-country {
    stroke: var(--border-color);
    stroke-width: 0.3;
    vector-effect: non-scaling-stroke;
    transition: fill var(--transition-speed);
}
.dash-map-country[data-has-data='1'] {
    cursor: pointer;
}
.dash-map-country:hover {
    stroke: var(--accent-primary);
    stroke-width: 1.2;
}

/* Errors tab (Crashalytics) */
.dash-errfilter {
    margin-bottom: 1rem;
    text-transform: capitalize;
}
.dash-badge {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    border-radius: 4px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    color: #fff;
}
.dash-badge.lvl-fatal {
    background: #b91c1c;
}
.dash-badge.lvl-error {
    background: var(--error-color);
}
.dash-badge.lvl-warning {
    background: #d97706;
}
.dash-badge.lvl-info {
    background: var(--accent-primary);
}
.dash-layer {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    border: 1px solid transparent;
}
.dash-layer.lyr-ui {
    color: var(--accent-primary);
    border-color: var(--accent-primary);
}
.dash-layer.lyr-be {
    color: var(--accent-secondary);
    border-color: var(--accent-secondary);
}
.dash-layer.lyr-db {
    color: #d97706;
    border-color: #d97706;
}
.dash-issues .dash-issue-row {
    cursor: pointer;
}
.dash-issues .dash-issue-row:hover {
    background: var(--bg-tertiary);
}
.dash-issue-title {
    display: flex;
    flex-direction: column;
    max-width: 46ch;
}
.dash-issue-name {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dash-issue-culprit {
    font-size: 0.75rem;
    color: var(--text-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.dash-issue-badge {
    font-size: 0.72rem;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    text-transform: capitalize;
}
.dash-issue-badge.is-unresolved {
    color: var(--error-color);
}
.dash-issue-badge.is-resolved {
    color: var(--success-color);
}
.dash-issue-ago {
    color: var(--text-muted);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.dash-issue-head {
    margin-bottom: 0.5rem;
}
.dash-issue-h2 {
    font-size: 1.15rem;
    margin: 0.5rem 0 0.25rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--text-primary);
}
.dash-issue-meta {
    font-size: 0.82rem;
    color: var(--text-secondary);
    margin-bottom: 0.6rem;
}
.dash-issue-status {
    text-transform: capitalize;
}
.dash-stack {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.8rem;
    overflow-x: auto;
}
.dash-frame {
    padding: 0.15rem 0.4rem;
    border-left: 3px solid transparent;
    white-space: nowrap;
}
.dash-frame.in-app {
    border-left-color: var(--accent-primary);
    background: var(--bg-tertiary);
}
.dash-frame-fn {
    color: var(--text-primary);
}
.dash-frame-loc {
    color: var(--text-muted);
}
.dash-crumbs {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.82rem;
}
.dash-crumb-cat {
    display: inline-block;
    min-width: 5rem;
    color: var(--accent-secondary);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.75rem;
}

/* Notes + live indicator */
.dash-note {
    font-size: 0.8rem;
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.dash-note i {
    color: var(--accent-primary);
}
.dash-live-dot {
    color: var(--success-color);
    font-size: 0.6rem;
    vertical-align: middle;
    animation: dash-pulse 1.6s ease-in-out infinite;
}
@keyframes dash-pulse {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.25;
    }
}
@media (prefers-reduced-motion: reduce) {
    .dash-live-dot {
        animation: none;
    }
}

@media (max-width: 820px) {
    .dash-main {
        grid-template-columns: 1fr;
    }
    .dash-tabs {
        flex-direction: row;
        flex-wrap: wrap;
        position: static;
    }
    .dash-tab {
        width: auto;
        border-left: none;
        border-bottom: 3px solid transparent;
        white-space: nowrap;
    }
    .dash-tab.active {
        border-left: none;
        border-bottom-color: var(--accent-primary);
    }
    .dash-toolbar {
        margin-left: 0;
    }
}

/* Import Card form */

/* Runs edge-to-edge, unlike the other admin views. This is a ~20-field data-entry form sat
   next to a card-art preview, and the shared 1100px .admin-main column squeezes the fields
   into needless wrapping while leaving the art thumbnail-sized. Scoped to this view so Tools
   and the rest of /admin keep their centred, readable column. */
#admin-import-card-view .admin-main {
    max-width: none;
}

.ic-urlbar {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    flex-wrap: wrap;
}
.ic-urlbar .ic-input {
    flex: 1;
    min-width: 240px;
}
/* Import is .btn-primary, which is `width: 100%` for the form/landing buttons it was built
   for. Inside this flex row that stretches it to a full-width bar which then wraps onto its
   own line below Parse. Size it like its neighbours (same fix as .admin-header .btn). */
.ic-urlbar .btn {
    width: auto;
}
.ic-status {
    min-height: 1.4rem;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    color: var(--text-secondary);
}
.ic-status.is-success {
    color: var(--success-color);
}
.ic-status.is-error {
    color: var(--error-color);
}
.ic-layout {
    display: grid;
    /* The art column grows with the viewport instead of sitting at a fixed 260px, so the
       preview is actually legible for proofreading rules text against the form. Capped at
       480px: past that the card outgrows the sticky viewport height and you lose the bottom
       of it while scrolling the fields. */
    grid-template-columns: clamp(300px, 27vw, 480px) 1fr;
    gap: 1.5rem;
    align-items: start;
}
.ic-preview {
    position: sticky;
    top: 5rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.ic-art {
    width: 100%;
    border-radius: 12px;
    border: 1px solid var(--border-color);
    background: var(--bg-tertiary);
    min-height: 160px;
    display: none;
    transition: transform 0.25s ease;
}

/* Art-preview rotation (flip cards / planar cards). */
.ic-art.rot-180 {
    transform: rotate(180deg);
}
.ic-art.rot-90 {
    transform: rotate(90deg);
}

.ic-art-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

/* .btn's inline-flex display would otherwise defeat the [hidden] attribute these
   buttons are toggled with (same fix as .help-nav-item[hidden]). */
.ic-art-controls .btn[hidden],
.ic-add[hidden],
.scan-capture-btn[hidden] {
    display: none;
}

/* Artist name in the card's native script, shown beside the field label. */
.ic-hint {
    color: var(--text-secondary);
    font-weight: 400;
    font-size: 0.85em;
}
.ic-price {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.ic-price-row {
    display: flex;
    justify-content: space-between;
    padding: 0.25rem 0.6rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    font-size: 0.9rem;
    color: var(--text-secondary);
}
.ic-price-row strong {
    color: var(--text-primary);
}
.ic-form {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}
.ic-row {
    display: flex;
    gap: 0.9rem;
    flex-wrap: wrap;
}
.ic-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    flex: 1 1 140px;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.ic-field.ic-grow {
    flex: 2 1 220px;
}
.ic-field.ic-full {
    flex-basis: 100%;
}
.ic-field.ic-check {
    flex-direction: row;
    align-items: center;
    gap: 0.4rem;
    flex: 0 0 auto;
    align-self: center;
}
.ic-input {
    width: 100%;
    padding: 0.5rem 0.7rem;
    background: var(--bg-secondary);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    font-size: 0.95rem;
    font-family: inherit;
}
.ic-input:focus {
    outline: none;
    border-color: var(--accent-primary);
}
textarea.ic-input {
    resize: vertical;
}
.ic-input-with-action {
    display: flex;
    gap: 0.4rem;
}
.ic-input-with-action .ic-input {
    flex: 1;
}
/* Wraps every single-line text input (readonly/select/checkbox/textarea fields don't get one)
   so a "×" clear button can sit inside its right edge — same pattern as .uv-search-clear. On
   the three fields that also have an .ic-add "+" button (name/type-line/artist), this wrapper
   is nested inside .ic-input-with-action so the two buttons sit side by side instead of
   overlapping: clear glyph over the input's own right edge, add button further right as a
   separate flex item. */
.ic-input-clear {
    position: relative;
    display: flex;
}
/* `flex: 1` only makes sense where .ic-input-clear shares a ROW-direction parent with something
   else to fill space next to (.ic-input-with-action's "+" button, or .ic-urlbar's other
   buttons). As a direct child of .ic-field (a COLUMN flex container), `flex: 1` would instead
   grow it to fill whatever extra height .ic-field's own column got stretched to by a taller
   sibling field in the same .ic-row (e.g. one with an .ic-error message) — inflating this
   field's input to match, even though nothing about this field itself is taller. */
.ic-input-with-action .ic-input-clear,
.ic-urlbar .ic-input-clear {
    flex: 1;
}
.ic-urlbar .ic-input-clear {
    min-width: 240px;
}
.ic-input-clear .ic-input {
    padding-right: 1.8rem;
}
.ic-clear-btn {
    position: absolute;
    top: 50%;
    right: 0.35rem;
    transform: translateY(-50%);
    display: flex;
    padding: 0.2rem;
    border: 0;
    background: none;
    color: var(--text-muted);
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--transition-speed);
}
/* Reveal only while hovering the field or while it (or the button itself) has focus — keeps the
   glyph out of the way until it's actually relevant, but still keyboard-reachable via Tab. The
   [hidden] rule below still wins over this when the field is empty (nothing to clear).

   The reveal is opacity ONLY: gating `pointer-events` on :hover too made the button unclickable
   until something had already hovered or focused the field, so a tap went to the input instead
   of the button (two taps to clear on touch) and a click on a field filled programmatically —
   e.g. by Parse — was swallowed by the input underneath. Nothing is lost by dropping it: the
   button exists only when the field has a value, and any pointer close enough to click it is
   already inside .ic-input-clear, which has made the glyph visible. */
.ic-input-clear:hover .ic-clear-btn,
.ic-input-clear:focus-within .ic-clear-btn {
    opacity: 1;
}
/* Without hover there is nothing to reveal on, so the glyph would only ever appear once the
   field had focus. Show it whenever there is a value. */
@media (hover: none) {
    .ic-clear-btn {
        opacity: 1;
    }
}
.ic-clear-btn:hover,
.ic-clear-btn:focus-visible {
    color: var(--accent-primary);
}
/* `display: flex` above beats the UA stylesheet's `[hidden] { display: none }` (same fix as
   .uv-search-clear[hidden]). */
.ic-clear-btn[hidden] {
    display: none;
}
.ic-error {
    color: var(--error-color);
    font-size: 0.78rem;
    min-height: 0.9rem;
}
@media (max-width: 760px) {
    .ic-layout {
        grid-template-columns: 1fr;
    }
    .ic-preview {
        position: static;
        max-width: 340px;
    }
}

/* ============================================================
   User Voice — public feedback board (board / submit / detail)
   ============================================================ */
.uv-main {
    max-width: 820px;
    margin: 0 auto;
    width: 100%;
}
.uv-status {
    min-height: 1.2rem;
    font-size: 0.9rem;
    color: var(--text-secondary);
}
.uv-status.is-error {
    color: var(--error-color);
}
.uv-status.is-success {
    color: var(--success-color);
}

/* Board toolbar (filters + sort). */
.uv-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-bottom: 0.75rem;
}
.uv-filter {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
/* Search sits in the same toolbar row as the three selects, but grows to take the slack —
   titles are long and the selects are not. */
.uv-filter--search {
    flex: 1 1 220px;
    min-width: 180px;
}
.uv-search-wrap {
    position: relative;
    display: block;
}
.uv-search {
    width: 100%;
    padding: 0.4rem 2rem 0.4rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font: inherit;
}
.uv-search:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 1px;
}
/* Hide the UA's own clear affordance — we ship one that matches the Sets filter. */
.uv-search::-webkit-search-cancel-button {
    appearance: none;
}
.uv-search-clear {
    position: absolute;
    top: 50%;
    right: 0.35rem;
    transform: translateY(-50%);
    display: flex;
    padding: 0.2rem;
    border: 0;
    background: none;
    color: var(--text-muted);
    cursor: pointer;
}
.uv-search-clear:hover,
.uv-search-clear:focus-visible {
    color: var(--accent-primary);
}
/* `display: flex` above beats the UA stylesheet's `[hidden] { display: none }`, so the
   attribute alone would NOT hide this button. Any author `display` on an element toggled via
   `hidden` needs this. */
.uv-search-clear[hidden] {
    display: none;
}
.uv-filter select {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
}

/* Board list. */
.uv-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.uv-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--border-color);
    border-radius: 12px;
    background: var(--bg-secondary);
    box-shadow: var(--shadow-sm);
}
.uv-score {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 52px;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-tertiary);
    line-height: 1.1;
}
.uv-score strong {
    font-size: 1.05rem;
}
.uv-score span {
    font-size: 0.65rem;
    text-transform: uppercase;
    color: var(--text-secondary);
}
.uv-item-main {
    min-width: 0;
    flex: 1;
}
.uv-item-title {
    display: block;
    font-weight: 600;
    color: var(--text-primary);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.uv-item-title:hover {
    color: var(--accent-primary);
}
.uv-item-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.35rem;
}
.uv-meta-count {
    font-size: 0.78rem;
    color: var(--text-secondary);
}

/* Badges (type + status). */
.uv-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.12rem 0.55rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    border: 1px solid transparent;
    white-space: nowrap;
}
.uv-type--Defect {
    background: rgba(239, 68, 68, 0.14);
    color: #ef4444;
}
.uv-type--Enhancement {
    background: rgba(34, 197, 94, 0.16);
    color: var(--success-color);
}
.uv-type--Question {
    background: rgba(139, 92, 246, 0.16);
    color: var(--accent-secondary);
}
/* Light theme only: --success-color / --accent-secondary on the pale 16%-alpha badge tints are
   1.99:1 / 3.46:1 (WCAG AA fail). Darker green/purple clear them (~6.3:1 / 5.8:1); dark theme
   keeps the lighter tokens, which read fine on its dark tints. */
:root:not([data-theme='dark']) .uv-type--Enhancement {
    color: #166534;
}
:root:not([data-theme='dark']) .uv-status--OnRoadmap {
    color: #6d28d9;
}
.uv-status--Submitted {
    background: var(--bg-tertiary);
    color: var(--text-secondary);
}
.uv-status--UnderReview {
    background: rgba(2, 119, 189, 0.14);
    color: var(--accent-primary);
}
.uv-status--OnRoadmap {
    background: rgba(139, 92, 246, 0.16);
    color: var(--accent-secondary);
}
.uv-status--Done {
    background: rgba(34, 197, 94, 0.16);
    color: var(--success-color);
}
.uv-status--WontFix {
    background: rgba(239, 68, 68, 0.12);
    color: var(--error-color);
}
.uv-staff {
    background: var(--accent-primary);
    color: #fff;
}

/* Empty state. */
.uv-empty {
    text-align: center;
    padding: 2.5rem 1rem;
    color: var(--text-secondary);
}
.uv-empty i {
    font-size: 2rem;
    opacity: 0.5;
}

/* Submission form. */
.uv-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-width: 640px;
}
.uv-types {
    border: none;
    padding: 0;
    margin: 0;
}
.uv-types legend {
    font-size: 0.8rem;
    color: var(--text-secondary);
    padding: 0;
    margin-bottom: 0.4rem;
}
.uv-type-group {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}
/* Visually-hidden radio; keeps keyboard + screen-reader semantics of a real radiogroup. */
.uv-type-radio {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    opacity: 0;
    pointer-events: none;
}
/* Raised ("up") toggle button — one per type. */
.uv-type-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1 1 auto;
    justify-content: center;
    min-width: 120px;
    padding: 0.6rem 1rem;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-weight: 600;
    cursor: pointer;
    user-select: none;
    box-shadow:
        var(--shadow-sm),
        inset 0 -2px 0 rgba(0, 0, 0, 0.1);
    transition:
        transform 0.08s ease,
        box-shadow 0.12s ease,
        background 0.12s ease,
        color 0.12s ease,
        border-color 0.12s ease;
}
.uv-type-btn i {
    font-size: 1.05rem;
}
.uv-type-btn:hover {
    border-color: var(--text-secondary);
    color: var(--text-primary);
}
/* Pressed ("down") + type-tinted state for the selected radio. */
.uv-type-radio:checked + .uv-type-btn {
    transform: translateY(1px);
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.22);
}
.uv-type-radio:checked + .uv-type-btn--Defect {
    background: rgba(239, 68, 68, 0.16);
    color: #ef4444;
    border-color: #ef4444;
}
.uv-type-radio:checked + .uv-type-btn--Enhancement {
    background: rgba(34, 197, 94, 0.16);
    color: var(--success-color);
    border-color: var(--success-color);
}
.uv-type-radio:checked + .uv-type-btn--Question {
    background: rgba(139, 92, 246, 0.18);
    color: var(--accent-secondary);
    border-color: var(--accent-secondary);
}
.uv-type-radio:focus-visible + .uv-type-btn {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}
.uv-field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-weight: 600;
    color: var(--text-primary);
}
.uv-field input,
.uv-field textarea {
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font: inherit;
    font-weight: 400;
}
.uv-field textarea {
    resize: vertical;
}
.uv-optional {
    font-weight: 400;
    font-size: 0.78rem;
    color: var(--text-secondary);
}
.uv-form-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
}

/* Detail page. */
.uv-detail-head {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.uv-detail-title {
    margin: 0.25rem 0;
    font-size: 1.4rem;
}
.uv-detail-sub {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin-bottom: 1rem;
}
.uv-detail-desc {
    line-height: 1.6;
    margin-bottom: 1rem;
}
.uv-attachments {
    list-style: none;
    padding: 0;
    margin: 0 0 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}
.uv-attachments a {
    color: var(--accent-primary);
    word-break: break-all;
}
.uv-vote-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--border-color);
    border-radius: 12px;
    background: var(--bg-secondary);
    margin-bottom: 1rem;
}
.uv-score-big {
    margin-right: auto;
    font-size: 1rem;
}
.uv-vote.is-active {
    background: var(--accent-primary);
    color: #fff;
    border-color: var(--accent-primary);
}
.uv-budget {
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.uv-signin-note {
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.uv-admin {
    margin-bottom: 1rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.uv-admin select {
    margin-left: 0.4rem;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
}

/* Comments. */
.uv-comments {
    border-top: 1px solid var(--border-color);
    padding-top: 1rem;
}
.uv-comments h2 {
    font-size: 1.1rem;
    margin-bottom: 0.75rem;
}
.uv-comment {
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-secondary);
    margin-bottom: 0.6rem;
}
.uv-comment.is-staff {
    border-color: var(--accent-primary);
    background: rgba(2, 119, 189, 0.06);
}
.uv-comment-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
    font-size: 0.82rem;
}
.uv-comment-who {
    font-weight: 600;
}
.uv-comment-date {
    margin-left: auto;
    color: var(--text-secondary);
}
.uv-comment-body {
    line-height: 1.5;
}
.uv-empty-note {
    color: var(--text-secondary);
    font-size: 0.9rem;
}
.uv-comment-form {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.uv-comment-form textarea,
.uv-comment-form input {
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font: inherit;
}
.uv-comment-form button {
    align-self: flex-start;
}
@media (max-width: 640px) {
    .uv-toolbar {
        gap: 0.6rem;
    }
    .uv-filter {
        flex: 1;
    }
}

/* ── Analytics consent banner (js/core/analytics-transport.js) ─────────────── */
.consent-banner {
    position: fixed;
    left: 20px;
    bottom: 20px;
    z-index: 1200;
    display: flex;
    gap: 14px;
    align-items: flex-start;
    width: 380px;
    max-width: calc(100vw - 40px);
    padding: 18px 20px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
    border-radius: 16px;
    box-shadow: var(--shadow-lg);
    font-size: 0.85rem;
    line-height: 1.55;
    animation: consent-in 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes consent-in {
    from {
        opacity: 0;
        transform: translateY(16px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.consent-icon {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border-radius: 12px;
    background: var(--bg-tertiary);
    background: color-mix(in srgb, var(--accent-primary) 15%, transparent);
    color: var(--accent-primary);
}

.consent-icon svg {
    width: 22px;
    height: 22px;
}

.consent-title {
    margin-bottom: 3px;
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--text-primary);
}

.consent-text {
    margin: 0 0 14px;
    color: var(--text-secondary);
}

.consent-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

.consent-btn {
    font: inherit;
    font-weight: 600;
    font-size: 0.82rem;
    padding: 7px 16px;
    border-radius: 8px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: var(--transition-interactive);
}

.consent-btn-primary {
    background: var(--accent-fill);
    color: #fff;
}

.consent-btn-primary:hover {
    background: var(--accent-fill-hover);
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.consent-btn-ghost {
    background: transparent;
    color: var(--text-secondary);
    border-color: var(--border-color);
}

.consent-btn-ghost:hover {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.consent-btn:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}

@media (max-width: 480px) {
    .consent-banner {
        left: 12px;
        right: 12px;
        bottom: 12px;
        width: auto;
    }
}

/* Consent control inside the Legal Info "Usage Analytics" card */
.analytics-consent-control {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 14px 0 18px;
    padding: 14px 16px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
}

.analytics-consent-status {
    color: var(--text-secondary);
}

.analytics-consent-status strong {
    color: var(--text-primary);
}

.analytics-consent-buttons {
    display: flex;
    gap: 8px;
}

.consent-btn[aria-pressed='true'] {
    outline: 2px solid var(--accent-primary);
    outline-offset: 1px;
}

.consent-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ---- Card scan (M11d step 4) ---- */
.scan-capture {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1.2rem;
    margin-bottom: 1rem;
}
.scan-camera {
    flex: 1 1 320px;
    max-width: 420px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
}
/* Camera-unavailable panel: same dashed frame as the drop zone opposite it (it borrows
   .file-drop-zone for that), sized and centred to match so the two halves read as a pair of
   choices. min-height rather than a fixed height so a long translated message can grow it. */
.scan-camera-note {
    width: 100%;
}
.scan-camera-panel {
    width: 100%;
    min-height: 260px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    /* Reset the UA button look — .file-drop-zone supplies the frame. */
    background: none;
    color: var(--text-secondary);
    font: inherit;
    cursor: pointer;
}
/* .file-drop-zone gives its icon a 1rem bottom margin, which double-counts against the gap. */
.scan-camera-panel i {
    margin-bottom: 0.2rem;
}
.scan-camera-msg {
    margin: 0;
}
.scan-camera-retry-hint {
    color: var(--accent-primary);
    font-weight: 600;
}
.scan-video {
    width: 100%;
    max-width: 420px;
    border-radius: 12px;
    background: #000;
}
.scan-camera-note {
    color: var(--text-muted);
    font-size: 0.85rem;
    text-align: center;
    margin: 0;
}
.scan-or {
    align-self: center;
    color: var(--text-muted);
    font-size: 0.85rem;
    text-transform: uppercase;
}
.scan-drop-zone {
    flex: 1 1 320px;
    max-width: 420px;
}
.scan-status {
    min-height: 1.4rem;
    margin: 0.4rem 0 1rem;
}
.scan-status-info {
    color: var(--text-secondary);
}
.scan-status-warn {
    color: var(--warning-color, #e6a700);
}
.scan-status-error {
    color: var(--error-color);
}
.scan-preview {
    text-align: center;
    margin-bottom: 1rem;
}
.scan-preview-caption {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin: 0 0 0.4rem;
}
.scan-preview-canvas {
    max-width: 224px;
    width: 100%;
    height: auto;
    border-radius: 8px;
    border: 1px solid var(--border-color);
}
.scan-candidates-title {
    margin: 0 0 0.6rem;
}
.scan-alternates-title {
    margin: 1.2rem 0 0.6rem;
    color: var(--text-secondary);
    font-size: 0.95rem;
}
.scan-candidate {
    cursor: pointer;
}
.scan-candidate-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    color: var(--text-secondary);
    font-size: 0.85rem;
}
.scan-distance {
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}
.scan-candidate-add {
    margin-top: 0.5rem;
    width: 100%;
}
/* ---- Card scan (M11d step 5b: quota line + commit dialog) ---- */
.scan-quota {
    color: var(--text-secondary);
    margin: 0 0 0.8rem;
    text-align: center;
}
/* On a capped plan the quota line links to the supporter page — the line names a limit, so
   it is also the most natural place to offer lifting it. Underlined only on hover/focus so
   it stays a quiet status line rather than reading as a call to action. */
.scan-quota-link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted currentcolor;
    transition: color var(--transition-speed);
}
.scan-quota-link:hover,
.scan-quota-link:focus-visible {
    color: var(--accent-primary);
    border-bottom-color: var(--accent-primary);
}
.scan-quota-link:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 3px;
}
.scan-add-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.scan-add-note {
    min-height: 1.2rem;
    color: var(--text-secondary);
}

/* ---- Card scan (M11d step 6: confidence gate + quality guard) ---- */
.scan-low-confidence-area {
    margin-top: 0.8rem;
}
.scan-low-confidence-note {
    color: var(--warning-color, #e6a700);
    font-size: 0.85rem;
    margin: 0 0 0.6rem;
}
.scan-confidence-hint {
    color: var(--warning-color, #e6a700);
    font-size: 0.85rem;
    margin: 0 0 0.6rem;
}

/* ---- Card-scan benchmark harness (M11d step 6, dev-only — /scan?bench=1) ---- */
.scanbench-note {
    color: var(--text-muted);
    font-size: 0.85rem;
    background: var(--bg-tertiary);
    border-radius: 8px;
    padding: 0.6rem 0.8rem;
    margin: 0 0 1rem;
}
.scanbench-setup {
    display: grid;
    gap: 0.8rem;
    margin-bottom: 1rem;
}
.scanbench-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}
.scanbench-field-row {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
}
.scanbench-field label {
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.scanbench-field input,
.scanbench-field select {
    padding: 0.4rem 0.6rem;
    border-radius: 6px;
    border: 1px solid var(--border-color);
    background: var(--bg-secondary);
    color: var(--text-primary);
}
.scanbench-gt-results {
    position: relative;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--bg-secondary);
    max-height: 220px;
    overflow-y: auto;
}
.scanbench-gt-result {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.4rem 0.6rem;
    background: none;
    border: none;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-primary);
    cursor: pointer;
}
.scanbench-gt-result:hover {
    background: var(--bg-tertiary);
}
.scanbench-gt-result-set {
    color: var(--text-muted);
    font-size: 0.8rem;
    margin-left: 0.4rem;
}
.scanbench-gt-selected {
    color: var(--text-secondary);
    font-size: 0.9rem;
}
.scanbench-attrs {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.8rem;
}
.scanbench-attrs-label {
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.scanbench-reprint-label input {
    width: 5rem;
    margin-left: 0.3rem;
}
.scanbench-frames {
    flex-direction: row;
    align-items: center;
    gap: 1rem;
}
.scanbench-capture {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1.2rem;
    margin-bottom: 1rem;
}
.scanbench-camera {
    flex: 1 1 320px;
    max-width: 420px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
}
.scanbench-video {
    width: 100%;
    max-width: 420px;
    border-radius: 12px;
    background: #000;
}
.scanbench-camera-note {
    color: var(--text-muted);
    font-size: 0.85rem;
    text-align: center;
    margin: 0;
}
.scanbench-or {
    align-self: center;
    color: var(--text-muted);
    font-size: 0.85rem;
    text-transform: uppercase;
}
.scanbench-drop-zone {
    flex: 1 1 320px;
    max-width: 420px;
}
.scanbench-tally {
    color: var(--text-secondary);
    margin: 0 0 0.8rem;
}
.scanbench-preview {
    text-align: center;
    margin-bottom: 1rem;
}
.scanbench-preview-caption {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin: 0 0 0.4rem;
}
.scanbench-table-wrap {
    overflow-x: auto;
    margin-bottom: 1rem;
}
.scanbench-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.82rem;
}
.scanbench-table th,
.scanbench-analysis-table th,
.scanbench-gate-table th {
    text-align: left;
    padding: 0.4rem 0.6rem;
    color: var(--text-secondary);
    font-weight: 600;
    border-bottom: 1px solid var(--border-color);
    white-space: nowrap;
}
.scanbench-table td,
.scanbench-analysis-table td,
.scanbench-gate-table td {
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-primary);
    white-space: nowrap;
}
.scanbench-table-set {
    color: var(--text-muted);
    font-size: 0.8rem;
}
.scanbench-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 1rem;
}
.scanbench-analysis {
    border-top: 1px solid var(--border-color);
    padding-top: 1rem;
}
.scanbench-analysis-table,
.scanbench-gate-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.82rem;
    margin-bottom: 1rem;
    overflow-x: auto;
    display: block;
}
.scanbench-verdict-pass {
    color: var(--success-color);
    font-weight: 700;
}
.scanbench-verdict-fail {
    color: var(--error-color);
    font-weight: 700;
}
.scanbench-gate-pass td:last-child {
    color: var(--success-color);
    font-weight: 600;
}
.scanbench-gate-fail td:last-child {
    color: var(--error-color);
    font-weight: 600;
}

/* ---- Browse: Sets index / Set / Card pages (js/browse.js) ---- */
.brx-container {
    max-width: 1100px;
    margin: 0 auto;
    /* Generous bottom padding so the floating app-nav never covers the last row/tile. */
    padding: 16px 16px 6rem;
}
.brx-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}
/* The wrapper carries the flex sizing the input used to; the input fills it so the
   absolutely-positioned clear button can sit inside the field's right edge. */
.brx-filter-wrap {
    position: relative;
    flex: 1 1 260px;
    min-width: 200px;
    display: flex;
}
.brx-sets-filter {
    flex: 1 1 auto;
    width: 100%;
    padding: 8px 34px 8px 12px; /* right pad clears the ✕ button */
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 0.95rem;
}
/* WebKit paints its own ✕ on type="search"; ours is the one that's themed and always present. */
.brx-sets-filter::-webkit-search-cancel-button {
    display: none;
}
.brx-filter-clear {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--border-color);
    color: var(--text-primary);
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}
.brx-filter-clear[hidden] {
    display: none;
}
.brx-filter-clear:hover {
    background: var(--text-muted);
    color: var(--bg-secondary);
}
/* Format filter: S / P / M letter toggles. Only Standard/Pioneer/Modern get chips — they
   are the three formats whose card pools have a real set cutoff, so they actually
   partition the list (Legacy/Vintage/Commander include essentially every set). Each is an
   independent push-down toggle carrying aria-pressed; the group is a role="group". */
.brx-format-filter {
    display: inline-flex;
    gap: 6px;
    flex: 0 0 auto;
}
.brx-fmt {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--border-color);
    border-radius: 50%;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    transition:
        background-color var(--transition-speed),
        border-color var(--transition-speed),
        color var(--transition-speed),
        box-shadow var(--transition-speed);
}
.brx-fmt:hover {
    border-color: var(--accent-primary);
    color: var(--text-primary);
}
/* Pressed = filled + inset shadow, so the "pushed down" state reads without relying on
   colour alone (the three accents below are a second, redundant cue). */
.brx-fmt.is-on {
    color: #fff;
    border-color: transparent;
    box-shadow: inset 0 2px 4px rgb(0 0 0 / 35%);
}
.brx-fmt.is-on[data-format='standard'] {
    background: #2e7d32;
}
.brx-fmt.is-on[data-format='pioneer'] {
    background: #1565c0;
}
.brx-fmt.is-on[data-format='modern'] {
    background: #6a1b9a;
}
.brx-fmt:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: 2px;
}
.brx-count {
    color: var(--text-muted);
    font-size: 0.85rem;
}
/* List / card view switch. `margin-left: auto` pushes it to the toolbar's trailing edge,
   away from the filter controls it is not part of. */
.brx-view-toggle {
    display: inline-flex;
    margin-left: auto;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
}
.brx-view-btn {
    width: 34px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-size: 0.85rem;
    cursor: pointer;
    transition:
        background-color var(--transition-speed),
        color var(--transition-speed);
}
.brx-view-btn + .brx-view-btn {
    border-left: 1px solid var(--border-color);
}
.brx-view-btn:hover {
    color: var(--text-primary);
}
.brx-view-btn.is-on {
    background: var(--accent-primary);
    color: #fff;
}
.brx-view-btn:focus-visible {
    outline: 2px solid var(--accent-primary);
    outline-offset: -2px;
}

/* ----- Sets card view ------------------------------------------------------
   auto-fill + minmax keeps the tiles a readable size at every width without media
   queries; the grid simply fits as many columns as it can. */
.brx-sets-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 14px;
    padding-bottom: 12px;
}
.brx-set-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    aspect-ratio: 4 / 3;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    overflow: hidden;
    background: var(--bg-secondary);
    text-decoration: none;
    transition:
        border-color var(--transition-speed),
        transform var(--transition-speed);
}
.brx-set-tile:hover {
    border-color: var(--accent-primary);
    transform: translateY(-2px);
}
/* The art layer, and the crop window: the image inside is scaled past this box on every
   side, so `overflow: hidden` here is what actually performs the crop. The gradient shows
   through for the ~160 sets with no priced booster card. Art is dimmed (below) so the
   expansion symbol and name stay legible — card art varies wildly in brightness, so that
   cannot be left to chance. */
.brx-set-tile-bg {
    position: absolute;
    inset: 0;
    overflow: hidden;
    background: linear-gradient(140deg, var(--bg-tertiary, #334155), var(--bg-secondary));
}
/* The art repo stores WHOLE cards (`.full.jpg`), so the frame is cropped away in CSS to
   leave just the art window. Fractions measured off real cards in the repo:

       modern frame (488x680)  art y 11.5%-56.2%, x 6.1%-93.9%
       old frame    (312x445)  art y  7.4%-54.6%, x 7.1%-92.9%

   Taking the INTERSECTION (top 11.5%, bottom 54.6%, left 7.1%, right 92.9%) means neither
   era ever shows frame edges — an old card just loses a sliver of art, which is invisible;
   overshooting the other way would put a title bar in the tile.

   Sizing, for a 4:3 tile: the art band is 43.1% of card height, so the image is scaled to
   125% of the tile width, which makes that band ~75% of the tile width — exactly the tile's
   height. translateY is simply the art's top fraction (aspect-independent); translateX is
   the art's left fraction plus half the horizontal overflow, to centre it. Both percentages
   resolve against the IMAGE's own box, which is why a different aspect ratio needs different
   `width` and translateX — hence the custom properties below.

   The two magic numbers, both measured in a browser rather than derived:
     · height 237% puts the visible band at 11.8%-54.4%, inside the art on BOTH eras. At
       232% it reached 55.3% and clipped ~2px of an old card's type line.
     · translateY -12%, not the art's exact 11.5%: at -11.5% a modern card showed a ~1px
       sliver of its title bar.
   `object-fit: cover` absorbs the two source aspects in the repo (0.718 and 0.701) by
   trimming a sliver of width instead of stretching, so the vertical fractions hold for both. */

/* ---- Shared full-card art crop -------------------------------------------------------
   Every art backdrop in the app (deck tiles, collection tiles and rows, set-page card
   tiles) shows the art window of a WHOLE card image from our repo, cropped in CSS. The
   geometry is the one measured for the Sets index above; only the numbers change per
   container, because the crop depends on the box's aspect ratio.

   So the mechanism lives here once and the four tuned values are custom properties. A view
   with a different aspect overrides them rather than reimplementing the crop — the thing
   the Sets version's own comment warns about ("changing the tile's aspect-ratio means
   recomputing width and translateX") is now a two-line override instead of a copy.

   Defaults are the Sets values (4:3). --art-w/--art-h scale the card so its art band fills
   the box; --art-x/--art-y slide that band into view. */
.card-art-crop {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: inherit;
    /* The layer covers its whole tile, so without this it swallows every click meant for the
       card underneath — it is decoration, never a target. */
    pointer-events: none;
}
.card-art-crop > img {
    position: absolute;
    top: 0;
    left: 0;
    /* Both EXPLICIT — see the deadlock note above: `height: auto` on an unloaded lazy image
       resolves to 0, so it never intersects the viewport and never loads. */
    width: var(--art-w, 125%);
    height: var(--art-h, 237%);
    object-fit: cover;
    transform: translate(var(--art-x, -10%), var(--art-y, -12%));
    opacity: var(--art-opacity, 0.55);
}
.brx-set-tile:hover .card-art-img {
    opacity: 0.7;
}
/* Big expansion symbol, centred in the art area above the caption. */
/* Format dots, top-right of a tile. Shown only while a format filter is active, in
   SET_FORMATS order (Standard, Pioneer, Modern), and coloured with the SAME three accents as
   the .brx-fmt chips above — the dot is only readable as "this is the Standard one" if it is
   literally the colour the Standard button is. */
.brx-set-tile-formats {
    position: absolute;
    top: 6px;
    right: 6px;
    /* Above the art and the centred set symbol, both of which it overlaps. */
    z-index: 2;
    display: flex;
    gap: 4px;
}
.brx-set-tile-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    /* A dark ring + shadow: the dots sit on card art of any brightness, and a flat colour
       chip can vanish into a light background without one. */
    box-shadow:
        0 0 0 1px rgb(0 0 0 / 50%),
        0 1px 2px rgb(0 0 0 / 45%);
}
.brx-set-tile-dot[data-format='standard'] {
    background: #2e7d32;
}
.brx-set-tile-dot[data-format='pioneer'] {
    background: #1565c0;
}
.brx-set-tile-dot[data-format='modern'] {
    background: #6a1b9a;
}
.brx-set-tile-symbol {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.brx-set-tile-symbol img,
.brx-set-tile-symbol svg {
    width: 56px;
    height: 56px;
    /* Set symbols are monochrome; force white and add a drop shadow so they read against
       both bright and dark art. */
    filter: brightness(0) invert(1) drop-shadow(0 2px 3px rgb(0 0 0 / 60%));
}
.brx-set-tile-meta {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 10px;
    background: linear-gradient(to top, rgb(0 0 0 / 78%), rgb(0 0 0 / 40%));
}
.brx-set-tile-name {
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.25;
    /* Long set names must not push the caption over the symbol. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.brx-set-tile-sub {
    color: rgb(255 255 255 / 75%);
    font-size: 0.72rem;
}
/* Sets index only: the toolbar and the table header stay put; just the rows scroll.
   The whole view becomes a flex column pinned to the viewport, and the row list is the
   single scrollable child. `min-height: 0` on each flex ancestor is what actually lets
   that child scroll instead of growing the page (default `min-height: auto` would keep
   expanding it). `.view[hidden]{display:none!important}` still wins over this display. */
#sets-view {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh; /* mobile: exclude the collapsing browser chrome */
    min-height: 0;
}
/* `body.has-app-nav` pads the page bottom to clear the fixed nav; stacked on the 100vh floor
   that `.view`/`#app` carry, the page becomes taller than the viewport and gains a dead
   scroll — which would drag this view's "frozen" toolbar out of sight. The analytics
   dashboard solves it by subtracting the nav height, but that number is duplicated per
   breakpoint (64px, 76px in the media query) and has to be kept in sync. This view is
   viewport-sized and already keeps its own nav clearance (.brx-container padding-bottom), so
   just drop the body padding while it's showing. `sets-active` is set by js/browse.js. */
body.sets-active.has-app-nav {
    padding-bottom: 0;
}
#sets-view .app-main {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    width: 100%;
    padding-bottom: 0;
}
#sets-view .brx-container {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* Ends above the floating app-nav rather than running underneath it. */
    padding-bottom: 5.5rem;
}
#sets-view .brx-toolbar {
    flex: 0 0 auto;
}
#sets-view .brx-sets-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}
.brx-sets-table {
    width: 100%;
    border-collapse: collapse;
}
/* Frozen header. `border-collapse: collapse` drops cell borders on sticky elements, so
   the divider is drawn as a box-shadow instead. */
.brx-sets-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--bg-primary);
    box-shadow: inset 0 -1px 0 var(--border-color);
}
.brx-sets-table th,
.brx-sets-table td {
    text-align: left;
    padding: 8px 10px;
    border-bottom: 1px solid var(--border-color);
    vertical-align: middle;
}
.brx-sets-table thead th {
    color: var(--text-muted);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.brx-th-icon,
.brx-td-icon {
    width: 40px;
}
.brx-th-code,
.brx-td-code {
    color: var(--text-secondary);
    font-family: ui-monospace, monospace;
    white-space: nowrap;
}
/* Every column reads left-aligned — header and cells together, so a header sits directly
   above its values instead of drifting to the far edge of a wide column. */
.brx-th-count,
.brx-td-count {
    text-align: left;
    color: var(--text-secondary);
    white-space: nowrap;
}
.brx-th-released,
.brx-td-released {
    text-align: left;
    color: var(--text-secondary);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.brx-set-icon {
    width: 26px;
    height: 26px;
    object-fit: contain;
    vertical-align: middle;
}
/* Set-symbol SVGs are solid black artwork, so they vanish on the dark theme — invert them
   (both the explicit toggle and the OS preference, matching how the app picks its theme). */
:root[data-theme='dark'] .brx-set-icon {
    filter: invert(1);
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) .brx-set-icon {
        filter: invert(1);
    }
}
/* Sortable column headers: the whole header is a button so it's keyboard-reachable. */
.brx-th-sortable {
    padding: 0;
}
.brx-sort-btn {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    padding: 8px 10px;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}
.brx-sort-btn:hover {
    color: var(--text-primary);
}
.brx-th-sortable.is-sorted .brx-sort-btn {
    color: var(--accent-primary);
}
.brx-sort-caret {
    font-size: 0.7em;
    line-height: 1;
}
/* Pill toggle (aria-pressed): outlined when off, accent-filled when on. */
.brx-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    transition:
        background-color var(--transition-speed),
        border-color var(--transition-speed),
        color var(--transition-speed);
}
.brx-pill:hover {
    border-color: var(--accent-primary);
    color: var(--text-primary);
}
.brx-pill.is-on {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: #fff;
}
/* Sub-set child rows: indented under their parent, quieter, and visually attached. */
.brx-row-subset {
    background: color-mix(in srgb, var(--bg-tertiary) 35%, transparent);
}
.brx-row-subset .brx-td-name {
    padding-left: 2.25rem;
    position: relative;
}
.brx-row-subset .brx-td-name::before {
    /* ↳ (U+21B3) reads as "child of the row above"; the box-drawing └ implied a
       continuous tree line that isn't drawn between siblings. */
    content: '↳';
    position: absolute;
    left: 1.1rem;
    color: var(--text-muted);
    /* The arrow sits higher on its baseline than the box-drawing glyph did. */
    line-height: 1.35;
}
.brx-subset-link {
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.9rem;
}
.brx-subset-link:hover {
    color: var(--accent-primary);
    text-decoration: underline;
}
.brx-set-link {
    color: var(--accent-primary);
    text-decoration: none;
    font-weight: 600;
}
.brx-set-link:hover {
    text-decoration: underline;
}
.brx-sets-table tbody tr:hover {
    background: var(--bg-tertiary);
}
.brx-back {
    display: inline-block;
    margin-bottom: 8px;
    color: var(--accent-primary);
    text-decoration: none;
    font-size: 0.9rem;
}
.brx-back:hover {
    text-decoration: underline;
}
.brx-set-head {
    margin-bottom: 16px;
}
.brx-set-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 4px 0;
    font-size: 1.4rem;
}
.brx-set-title .brx-set-icon {
    width: 32px;
    height: 32px;
}
.brx-set-code {
    font-family: ui-monospace, monospace;
    font-size: 0.8rem;
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 2px 6px;
}
.brx-section {
    margin: 20px 0;
}
.brx-section-title {
    font-size: 1.05rem;
    margin: 0 0 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-color);
}
.brx-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
}
.brx-card-tile {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    overflow: hidden;
    background: var(--bg-secondary);
    text-decoration: none;
    color: var(--text-primary);
    transition:
        transform 0.08s ease,
        box-shadow 0.08s ease;
}
.brx-card-tile:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}
.brx-tile-art {
    /* The tile's own art box: in normal flow with an aspect ratio, and the positioned
       ancestor for the .card-art-crop image inside it. Without these two lines the crop
       layer's `position: absolute; inset: 0` escapes to the view and every image renders
       at its natural 1588x2197. */
    position: relative;
    inset: auto;
    display: block;
    aspect-ratio: 626 / 457;
    overflow: hidden;
    background-color: var(--bg-tertiary);
    --art-opacity: 1;
}
.brx-tile-meta {
    padding: 6px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.brx-tile-name {
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.brx-tile-sub {
    display: flex;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--text-muted);
}
.brx-tile-price {
    color: var(--text-secondary);
}
.brx-card {
    display: grid;
    grid-template-columns: minmax(220px, 340px) 1fr;
    gap: 24px;
    align-items: start;
}
/* Reserve the card's aspect ratio and show a neutral plate, so a card whose art fails to
   load (offline, or a printing missing from the art repo) leaves a tidy placeholder
   rather than an empty column. */
.brx-card-image {
    aspect-ratio: 488 / 680;
    background: var(--bg-tertiary);
    border-radius: 16px;
    overflow: hidden;
}
.brx-card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: 16px;
    box-shadow: var(--shadow-lg);
}
.brx-card-name {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 1.5rem;
    margin: 0 0 12px;
}
.brx-card-facts {
    width: 100%;
    border-collapse: collapse;
}
.brx-card-facts th,
.brx-card-facts td {
    text-align: left;
    padding: 6px 8px;
    border-bottom: 1px solid var(--border-color);
    vertical-align: top;
}
.brx-card-facts th {
    color: var(--text-muted);
    font-weight: 600;
    white-space: nowrap;
    width: 120px;
}
.brx-card-oracle {
    margin-top: 14px;
    padding: 12px 14px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    line-height: 1.5;
}
.brx-error-actions {
    display: flex;
    gap: 10px;
    justify-content: center;
    margin-top: 12px;
}
@media (max-width: 680px) {
    .brx-card {
        grid-template-columns: 1fr;
    }
    .brx-card-image {
        /* `margin: 0 auto` opts a grid item out of `justify-self: stretch`, so without an
           explicit width the box shrink-to-fits its image — collapsing to 0×0 whenever the
           art fails to load. Pin the width so the placeholder plate always holds its space. */
        width: 100%;
        max-width: 340px;
        margin: 0 auto;
    }
}
