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

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
    color: #f1f1f1;
    min-height: 100vh;
    padding-bottom: 40px;
}

.container {
    max-width: 1400px;
    margin: 0 auto;
    padding: 10px;
    isolation: isolate;
}

header {
    text-align: center;
    padding: 30px 10px 25px;
    background: linear-gradient(135deg, #1a1a4e 0%, #2d1b69 30%, #1a3a5c 70%, #162447 100%);
    border-radius: 18px;
    margin-bottom: 20px;
    position: relative;
    overflow: hidden;
    border: 1px solid rgba(255, 215, 0, 0.15);
    box-shadow: 0 4px 30px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

.header-pokemon-bg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 0;
}

/* Colored card silhouette background decorations (gold-on-navy) */
.header-pokemon-bg .card-bg {
    position: absolute;
    opacity: 0.55;
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.35));
}
.header-pokemon-bg .card-bg.cb1 {
    left: -15px; top: 50%; transform: translateY(-50%) rotate(-15deg); width: 110px; height: 110px;
}
.header-pokemon-bg .card-bg.cb2 {
    right: -20px; bottom: -15px; transform: rotate(20deg); width: 100px; height: 100px;
}
.header-pokemon-bg .card-bg.cb3 {
    right: 30%; top: -15px; transform: rotate(10deg); width: 72px; height: 72px; opacity: 0.45;
}
.header-pokemon-bg .card-bg.cb4 {
    left: 25%; bottom: -10px; transform: rotate(-25deg); width: 64px; height: 64px; opacity: 0.4;
}

/* Real cartoon Pokemon character images */
.header-pokemon-bg .pokemon-char {
    position: absolute;
    bottom: 5px;
    height: auto;
    z-index: 1;
    filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.5));
    transition: transform 0.3s ease;
}
.header-pokemon-bg .pokemon-char:hover {
    transform: scale(1.08) translateY(-2px);
}
.header-pokemon-bg .pokemon-pikachu {
    right: 8px;
    width: 88px;
}
.header-pokemon-bg .pokemon-psyduck {
    left: 8px;
    width: 78px;
}
.header-pokemon-bg .pokemon-togepi {
    left: 50%;
    transform: translateX(-50%);
    bottom: -2px;
    width: 62px;
    opacity: 0.9;
}
.header-pokemon-bg .pokemon-togepi:hover {
    transform: translateX(-50%) scale(1.08) translateY(-2px);
}

/* Real pokeball PNG accents (floating) */
.header-pokemon-bg .pokeball-accent {
    position: absolute;
    z-index: 1;
    opacity: 0.85;
    width: 24px;
    height: 24px;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.4));
}
.header-pokemon-bg .pokeball-accent.pba1 {
    top: 8px; left: 18%;
    animation: float-pokeball 4s ease-in-out infinite;
}
.header-pokemon-bg .pokeball-accent.pba2 {
    width: 20px; height: 20px; top: 12px; right: 22%;
    animation: float-pokeball 5s ease-in-out infinite 1.5s;
}

@keyframes float-pokeball {
    0%, 100% { transform: translateY(0) rotate(0deg); }
    50% { transform: translateY(-4px) rotate(15deg); }
}

/* Floating sparkles */
.header-sparkle {
    position: absolute;
    width: 4px;
    height: 4px;
    background: #ffd700;
    border-radius: 50%;
    opacity: 0;
    animation: sparkle 3s ease-in-out infinite;
    z-index: 2;
}
.header-sparkle:nth-child(1) { left: 20%; top: 20%; animation-delay: 0s; }
.header-sparkle:nth-child(2) { left: 45%; top: 60%; animation-delay: 0.8s; }
.header-sparkle:nth-child(3) { left: 70%; top: 25%; animation-delay: 1.6s; }
.header-sparkle:nth-child(4) { left: 85%; top: 50%; animation-delay: 2.2s; }
.header-sparkle:nth-child(5) { left: 35%; top: 35%; animation-delay: 1.2s; width: 3px; height: 3px; }

@keyframes sparkle {
    0%, 100% { opacity: 0; transform: scale(0.5); }
    50% { opacity: 0.7; transform: scale(1.2); }
}

h1 {
    font-size: 1.8rem;
    margin-bottom: 8px;
    background: linear-gradient(45deg, #ffd700, #ffed4e, #ffd700);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    position: relative;
    z-index: 3;
    text-shadow: none;
    font-weight: 800;
    letter-spacing: 0.5px;
}

.logo-link {
    display: inline-block;
    position: relative;
    z-index: 3;
    text-decoration: none;
    margin-bottom: 4px;
}

.header-logo {
    width: min(420px, 85vw);
    height: auto;
    display: block;
    margin: 0 auto;
    filter: drop-shadow(0 2px 10px rgba(255, 215, 0, 0.85)) drop-shadow(0 0 4px rgba(255, 237, 78, 0.55)) brightness(1.08);
    transition: filter 0.3s ease, transform 0.3s ease;
}

.header-logo:hover {
    filter: drop-shadow(0 4px 20px rgba(255, 215, 0, 0.95)) drop-shadow(0 0 6px rgba(255, 237, 78, 0.7)) brightness(1.12);
    transform: scale(1.03);
}

.subtitle {
    font-size: 0.9rem;
    opacity: 0.8;
    position: relative;
    z-index: 3;
}

.sync-status {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    padding: 4px 10px;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.08);
    white-space: nowrap;
}

.sync-indicator {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #666;
}

.sync-indicator.synced { background: #00ff88; }
.sync-indicator.syncing { background: #ffaa00; animation: pulse 1s infinite; }
.sync-indicator.error { background: #ff4444; }

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* Block selection buttons */
.block-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 20px;
    justify-content: center;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: thin;
}

/* Collapse non-active era / set tiles once one is picked — applies to all
 * viewports and themes. Clicking the active tile again restores the full
 * list. The active tile keeps its grid cell so it pins to the row start. */
.block-buttons.has-selection .block-btn:not(.active),
.set-buttons.has-selection .set-btn:not(.active) {
    display: none;
}

@media (max-width: 767px) {
    .block-buttons {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
        overflow-x: visible;
    }
    .block-btn {
        min-width: unset;
        padding: 10px;
    }
    .block-btn-logo-wrapper { height: 35px; margin-bottom: 4px; }
    .block-btn-logo { max-height: 35px; }
    .block-btn-name { font-size: 0.8rem; margin-bottom: 4px; }
    .block-btn-stats { font-size: 0.65rem; }
    .block-btn-progress { margin-top: 6px; }
    .block-buttons.has-selection,
    .set-buttons.has-selection {
        grid-template-columns: 1fr;
    }
}

@media (min-width: 768px) {
    .block-buttons {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(280px, 340px));
        overflow-x: visible;
    }
}

.block-btn {
    --block-color: #888;
    padding: 20px;
    border: 3px solid;
    border-radius: 16px;
    color: #ffffff;
    font-size: 1.1rem;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.3s;
    text-align: center;
    position: relative;
    overflow: hidden;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--block-color) 35%, transparent) 0%,
        color-mix(in srgb, var(--block-color) 25%, transparent) 50%,
        color-mix(in srgb, var(--block-color) 35%, transparent) 100%);
    border-color: color-mix(in srgb, var(--block-color) 50%, transparent);
}

.block-btn::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--block-color) 20%, transparent),
        color-mix(in srgb, var(--block-color) 15%, transparent));
    opacity: 0;
    transition: opacity 0.3s;
}

.block-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5);
}

.block-btn:hover::before {
    opacity: 1;
}

.block-btn.active {
    transform: scale(1.05);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
}

.block-btn.active::before {
    opacity: 1;
}

.block-btn:active {
    transform: scale(0.98);
}

@media (max-width: 767px) {
    .block-btn.active {
        transform: none;
        box-shadow: 0 0 0 2px var(--block-color), 0 4px 16px rgba(0,0,0,0.5);
    }
}

.block-btn-content {
    position: relative;
    z-index: 1;
}

.block-btn-logo-wrapper {
    width: 100%;
    height: 50px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.block-btn-logo {
    max-width: 100%;
    max-height: 50px;
    object-fit: contain;
}

.block-btn-name {
    font-size: 1.1rem;
    font-weight: 700;
    margin-bottom: 8px;
}

.block-btn-stats {
    font-size: 0.75rem;
    opacity: 0.7;
    margin-top: 4px;
}

/* New per-era fields (year range + separate fraction/percent line) used by
 * the holofoil theme. Hidden in the scrapbook (default) theme so its tile
 * keeps its existing single-line stats display. */
.block-btn-meta,
.block-btn-stats-row { display: none; }

/* ── Promos & Specials toggle ───────────────────────────────────── */
/* Non-prominent (promo / festival / challenge) set tiles are hidden by
 * default in their rails so the mainline chapter sets dominate. A
 * `+ Promos & Specials (N)` button reveals them when the user clicks. */
.set-btn.non-prominent.is-collapsed { display: none !important; }

.promos-toggle-btn {
    flex: 0 0 auto;
    align-self: center;
    padding: 10px 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px dashed rgba(255, 255, 255, 0.25);
    color: rgba(241, 241, 241, 0.75);
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.3px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
    white-space: nowrap;
}
.promos-toggle-btn:hover,
.promos-toggle-btn:focus-visible {
    background: rgba(255, 255, 255, 0.10);
    border-color: rgba(255, 255, 255, 0.4);
    color: #fff;
}
.promos-toggle-icon {
    font-size: 1.1rem;
    line-height: 1;
    width: 16px;
    text-align: center;
}
.promos-toggle-count {
    padding: 1px 7px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.10);
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
}

.block-btn.active .block-btn-stats {
    opacity: 0.9;
}

/* Set selection buttons */
/* `auto-fit` (not `auto-fill`) so empty tracks collapse when there are
   fewer items than fit in the row — combined with justify-content:center
   this centers partial rows (e.g. Mega Evolution's 4 sets) instead of
   pinning them to the left edge. */
.set-buttons {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 260px));
    gap: 12px;
    margin-bottom: 20px;
    justify-content: center;
}

/* Hierarchical set buttons for Pokemon TCG (hidden until block selected) */
#pokemon-tcg-content .set-buttons {
    display: none;
}

#pokemon-tcg-content .set-buttons.active {
    display: grid;
    animation: slideDown 0.3s ease-out;
}

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

.set-btn {
    padding: 12px;
    border: none;
    border-radius: 10px;
    background: linear-gradient(135deg, rgba(255,255,255,0.08) 0%, var(--set-accent, rgba(255,255,255,0.08)) 100%);
    border-left: 3px solid var(--set-border, transparent);
    color: #f1f1f1;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    flex-direction: column;
    text-align: center;
    position: relative;
    overflow: hidden;
}

.set-btn:hover {
    filter: brightness(1.2);
    transform: translateY(-2px);
}

.set-btn.active {
    background: linear-gradient(135deg, #ff6b6b, #ee5a6f);
    border-left-color: transparent;
    box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
    filter: none;
    transform: none;
}

/* Keep logo fully visible on active button — active state indicated by border/glow */
.set-btn.active .set-btn-logo {
    opacity: 1;
}

.set-btn-logo-wrapper {
    position: relative;
    width: 100%;
    height: 100px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.set-btn-logo {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    z-index: 2;
    transition: opacity 0.3s ease;
}

/* When a real image replaces the SVG, blend it with the dark background
   so rectangular product images don't look like hard-edged boxes */
.set-btn-logo.logo-loaded {
    mix-blend-mode: lighten;
}

.set-btn-logo-fallback {
    font-size: 2.5rem;
    opacity: 0.9;
    filter: grayscale(30%);
    z-index: 1;
    display: block;
}

.set-btn-name {
    font-size: 0.9rem;
    font-weight: 600;
    margin-bottom: 4px;
}

.set-btn .set-release-date {
    font-size: 0.65rem;
    opacity: 0.5;
    margin-top: 2px;
}

/* Top-level tab bar */
.top-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 16px;
    background: rgba(0, 0, 0, 0.3);
    border-radius: 12px;
    padding: 4px;
}

.top-tab {
    flex: 1;
    padding: 12px 16px;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: rgba(241, 241, 241, 0.5);
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    text-align: center;
    white-space: nowrap;
}

.top-tab:hover {
    color: rgba(241, 241, 241, 0.8);
    background: rgba(255, 255, 255, 0.05);
}

.top-tab.active {
    background: rgba(255, 255, 255, 0.12);
    color: #f1f1f1;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

.top-tab-divider {
    width: 100%;
    height: 1px;
    margin: 2px 0;
    background: rgba(255, 255, 255, 0.08);
    flex-shrink: 0;
}

.top-tab-utility {
    flex: 1;
    font-size: 0.85rem;
    color: rgba(241, 241, 241, 0.4);
}

.top-tab-utility.active {
    background: rgba(37, 99, 235, 0.25);
    color: #93bbfc;
}

.top-tab-content {
    display: none;
    overflow: hidden;
}

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

@media (max-width: 768px) {
    .top-tabs {
        gap: 3px;
        padding: 3px;
    }

    .top-tab {
        padding: 8px 8px;
        font-size: 0.78rem;
    }

    .top-tab-utility {
        font-size: 0.75rem;
    }
}

.placeholder-content {
    text-align: center;
    padding: 60px 20px;
    background: rgba(255, 255, 255, 0.03);
    border-radius: 15px;
    border: 1px dashed rgba(255, 255, 255, 0.1);
}

.placeholder-content h2 {
    font-size: 1.5rem;
    margin-bottom: 12px;
    opacity: 0.9;
}

.placeholder-content p {
    font-size: 0.95rem;
    opacity: 0.5;
    line-height: 1.6;
}

.placeholder-content .coming-soon-badge {
    display: inline-block;
    padding: 6px 18px;
    border-radius: 20px;
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-top: 16px;
}

.coming-soon-badge.custom-sets {
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: #fff;
}

.coming-soon-badge.lorcana {
    background: linear-gradient(135deg, #f39c12, #e67e22);
    color: #fff;
}

/* Inline progress bar in set buttons */
.set-btn-progress {
    width: 100%;
    height: 5px;
    background: rgba(255, 255, 255, 0.15);
    border-radius: 4px;
    overflow: hidden;
    margin-top: 8px;
}

.set-btn-progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #00ff88, #00d4ff);
    transition: width 0.3s;
    border-radius: 4px;
}

.set-btn.active .set-btn-progress {
    background: rgba(255, 255, 255, 0.25);
}

.set-btn.active .set-btn-progress-fill {
    background: linear-gradient(90deg, #fff, #e0e0e0);
}

.set-btn-stats {
    font-size: 0.7rem;
    opacity: 0.7;
    margin-top: 4px;
}

.set-btn.active .set-btn-stats {
    opacity: 0.95;
}

/* Epic #497 — Custom Sets category section header. Spans the full rail grid
   row so tiles below it group visually under the tag label. */
.custom-set-category-header {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 8px 0 2px;
    padding: 0 2px;
    font-size: 0.95rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.92);
    text-transform: none;
}
.custom-set-category-header::after {
    content: '';
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, rgba(255,255,255,0.22), rgba(255,255,255,0));
}
.custom-set-category-label {
    white-space: nowrap;
    order: 0;
}
.custom-set-category-header::after { order: 1; }
.custom-set-category-count {
    flex: 0 0 auto;
    order: 2;
    font-size: 0.7rem;
    font-weight: 600;
    opacity: 0.7;
    padding: 1px 8px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.1);
}

/* Epic #497 Story 4 — personal-category marker. Person glyph rendered inline
   before an exclusively-personal category's label (rail header + filter pill).
   currentColor so it inherits the surrounding text color; slightly dimmed. */
.csc-personal-glyph {
    opacity: 0.65;
    margin-right: 5px;
    vertical-align: -1px;
}
/* Holofoil's rail/pill backgrounds are darker + busier, so bump contrast. */
[data-theme="holofoil"] .csc-personal-glyph {
    opacity: 0.8;
}
/* Non-glyph cue for personal filter pills — the 11px dimmed glyph alone is too
   weak for low-vision users to tell personal from shared. A currentColor
   left-edge accent + faint tint reads at a glance and is theme-safe (inherits
   the pill's text color in both default and holofoil). Kept subtle so the pill
   doesn't look broken. */
.csc-pill-personal {
    border-left: 2px solid currentColor;
    padding-left: 8px;
    background-color: rgba(127, 127, 127, 0.08);
}

.block-btn-progress {
    width: 100%;
    height: 6px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 4px;
    overflow: hidden;
    margin-top: 10px;
}

.block-btn-progress-fill {
    height: 100%;
    background: rgba(255, 255, 255, 0.5);
    transition: width 0.3s;
    border-radius: 4px;
}

.block-btn.active .block-btn-progress-fill {
    background: rgba(255, 255, 255, 0.9);
}

/* Helper text for navigation guidance */
.helper-text {
    text-align: center;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.5);
    margin-bottom: 16px;
    font-style: italic;
}


/* Set selection section header */
.set-selection-header {
    display: none;
    margin-top: 24px;
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 2px solid rgba(255, 255, 255, 0.1);
}

.set-selection-header.active {
    display: block;
}

.set-selection-title {
    font-size: 1rem;
    font-weight: 600;
    opacity: 0.7;
    text-transform: uppercase;
    letter-spacing: 1px;
}

.set-section {
    display: none;
}

.set-section.active {
    display: block;
}

/* New holofoil-only set header (logo + name + meta + progress). Hidden in
 * the scrapbook (default) theme so its set view is unchanged; the
 * holofoil rule shows + styles it. */
.set-header { display: none; }

/* Set view tabs (Cards / Sealed Products) */
.set-view-tabs {
    display: flex;
    gap: 2px;
    margin: 0 auto 16px auto;
    background: rgba(255, 255, 255, 0.04);
    border-radius: 10px;
    padding: 4px;
    width: fit-content;
}

.set-view-tab {
    padding: 7px 20px;
    border: none;
    border-radius: 7px;
    background: transparent;
    color: rgba(241, 241, 241, 0.55);
    font-size: 0.82rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
    letter-spacing: 0.3px;
}

.set-view-tab:hover {
    color: rgba(241, 241, 241, 0.8);
    background: rgba(255, 255, 255, 0.06);
}

.set-view-tab.active {
    background: rgba(255, 255, 255, 0.12);
    color: #f1f1f1;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

.set-view-content {
    display: none;
}

.set-view-content.active {
    display: block;
}

/* Sealed Products grid */
.sealed-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

.sealed-item {
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 10px;
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    transition: all 0.2s;
}

.sealed-item:hover {
    background: rgba(255, 255, 255, 0.11);
    border-color: rgba(255, 255, 255, 0.18);
    transform: translateY(-1px);
}

.sealed-item.owned {
    background: rgba(0, 255, 136, 0.07);
    border-color: rgba(0, 255, 136, 0.25);
}

.sealed-img-wrapper {
    width: 100%;
    aspect-ratio: 4/3;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: 6px;
    background: rgba(0, 0, 0, 0.2);
    position: relative;
}

.sealed-img-wrapper > img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Real product image overlaid on styled thumb */
.sealed-product-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #0d1b2a;
}

/* Styled thumbnail for fallback sealed products */
.sealed-thumb {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: linear-gradient(145deg, #0d1b2a, #0d1b2a);
    box-shadow: inset 0 0 60px 10px var(--thumb-color);
    border-radius: 4px;
    position: relative;
    overflow: hidden;
}

.sealed-thumb-symbol {
    width: 52px;
    height: 52px;
    object-fit: contain;
    filter: drop-shadow(0 1px 4px rgba(0,0,0,0.6));
    opacity: 0.9;
}

.sealed-thumb-icon {
    font-size: 1.3rem;
    line-height: 1;
    filter: drop-shadow(0 1px 3px rgba(0,0,0,0.5));
}

.sealed-img-placeholder {
    font-size: 2.5rem;
    opacity: 0.5;
}

.sealed-info {
    display: flex;
    flex-direction: column;
    gap: 6px;
    flex: 1;
}

.sealed-name {
    font-size: 0.83rem;
    font-weight: 500;
    line-height: 1.3;
    color: #f1f1f1;
}

.sealed-meta {
    display: flex;
    align-items: center;
    gap: 8px;
}

.sealed-qty-controls {
    display: flex;
    align-items: center;
    gap: 10px;
    justify-content: center;
}

.sealed-qty-btn {
    width: 30px;
    height: 30px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.15);
    background: rgba(255, 255, 255, 0.07);
    color: #f1f1f1;
    font-size: 1.1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
    line-height: 1;
    padding: 0;
}

.sealed-qty-btn:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.28);
}

.sealed-qty-value {
    font-size: 1rem;
    font-weight: 600;
    min-width: 24px;
    text-align: center;
    color: #f1f1f1;
}

.sealed-item.owned .sealed-qty-value {
    color: #00ff88;
}

.sealed-empty,
.sealed-loading {
    grid-column: 1 / -1;
    text-align: center;
    padding: 40px 20px;
    color: rgba(241, 241, 241, 0.45);
    font-size: 0.9rem;
    line-height: 1.6;
}

/* Card controls: filters and search */
.card-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 16px;
    align-items: center;
    justify-content: center;
}

.filter-buttons {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: center;
}

.filter-btn {
    padding: 8px 16px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    color: #f1f1f1;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
}

.filter-btn:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.25);
}

.filter-btn.active {
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-color: rgba(102, 126, 234, 0.4);
    box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
}

.search-container {
    flex: 1;
    min-width: 200px;
    max-width: 400px;
    position: relative;
}

.search-input {
    width: 100%;
    padding: 8px 36px 8px 12px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    color: #f1f1f1;
    font-size: 0.85rem;
    transition: all 0.2s;
}

.search-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

.search-input:focus {
    outline: none;
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(102, 126, 234, 0.5);
    box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}

.search-clear {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    color: rgba(255, 255, 255, 0.5);
    cursor: pointer;
    font-size: 1.2rem;
    padding: 0;
    width: 20px;
    height: 20px;
    display: none;
    align-items: center;
    justify-content: center;
    transition: color 0.2s;
}

.search-clear:hover {
    color: rgba(255, 255, 255, 0.8);
}

.search-clear.visible {
    display: flex;
}

/* Rarity filter toggle buttons */
.rarity-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    width: 100%;
    justify-content: center;
}

.rarity-btn {
    padding: 4px 10px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.06);
    color: rgba(241, 241, 241, 0.72);
    font-size: 0.65rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    white-space: nowrap;
}

.rarity-btn:focus-visible {
    outline: 2px solid #c5cdff;
    outline-offset: 2px;
}

.rarity-btn:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.3);
    color: rgba(241, 241, 241, 0.85);
}

.rarity-btn.active {
    background: rgba(102, 126, 234, 0.35);
    border-color: rgba(102, 126, 234, 0.6);
    color: #f1f1f1;
    box-shadow: 0 1px 6px rgba(102, 126, 234, 0.25);
}

/* Epic #497 Story 3 — Custom Sets category filter pills.
 * Reuses the rarity-pill visual language (.rarity-btn) but lives in its own
 * flex container so it does NOT inherit the rail's CSS grid. */
.custom-set-filter-pills {
    width: 100%;
}

.custom-set-filter-pills:empty {
    display: none;
}

.custom-set-filter-pills-group {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
    margin: 0 auto 14px;
    max-width: 900px;
}

/* Story 5.5 — graded filter
 *
 * Per-set pill row that narrows the card grid to graded-only / a specific
 * grading company. Pills mirror `.rarity-btn` visual weight but use a distinct
 * accent color (amber) so they read as a separate filter dimension. */
.graded-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    width: 100%;
    justify-content: center;
}

.filter-pill-graded {
    padding: 4px 10px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 20px;
    background: rgba(255, 255, 255, 0.06);
    color: rgba(241, 241, 241, 0.6);
    font-size: 0.65rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    white-space: nowrap;
}

.filter-pill-graded:hover {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.3);
    color: rgba(241, 241, 241, 0.85);
}

.filter-pill-graded.active {
    background: rgba(245, 158, 11, 0.3);
    border-color: rgba(245, 158, 11, 0.65);
    color: #ffeab3;
    box-shadow: 0 1px 6px rgba(245, 158, 11, 0.25);
}

@media (max-width: 768px) {
    .filter-pill-graded {
        padding: 3px 8px;
        font-size: 0.6rem;
    }
}

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

/* ── Compact list view (shared across Pokemon, Custom Sets, Lorcana) ──
 * Both .card-grid and .card-list live in the DOM at the same time. The
 * `.view-mode-list` / `.view-mode-grid` class on the parent .set-view-cards
 * wrapper toggles which one is visible — instant switch, no rebuild. */
.view-toggle {
    display: inline-flex;
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.05);
}
.view-toggle-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: transparent;
    color: rgba(241, 241, 241, 0.7);
    border: none;
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    text-transform: none;
    letter-spacing: 0;
}
.view-toggle-btn + .view-toggle-btn {
    border-left: 1px solid rgba(255, 255, 255, 0.15);
}
.view-toggle-btn:hover { color: #f1f1f1; background: rgba(255, 255, 255, 0.06); }
.view-toggle-btn.active {
    background: rgba(0, 255, 136, 0.18);
    color: #00ff88;
    box-shadow: inset 0 0 0 1px rgba(0, 255, 136, 0.35);
}
.view-toggle-btn:focus-visible {
    outline: 2px solid rgba(0, 255, 136, 0.7);
    outline-offset: 2px;
    z-index: 1;
}
.view-toggle-btn svg { display: block; }

.card-list {
    display: none;
    flex-direction: column;
    gap: 2px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.03);
    overflow: hidden;
}

/* View-mode visibility — sibling containers, only one shows. */
.set-view-cards.view-mode-list .card-grid { display: none; }
.set-view-cards.view-mode-list .card-list { display: flex; }
.set-view-cards.view-mode-grid .card-grid { display: grid; }
.set-view-cards.view-mode-grid .card-list { display: none; }

.card-list-row {
    display: grid;
    /* num · name (greedy) · rarity · variants · price · status.
     * Name uses minmax(0, 1fr) so its nowrap text can shrink and ellipsize
     * instead of forcing the track to the full string width. Non-name tracks
     * are kept tight so the name cell wins the remaining space. The num track
     * holds labels up to promo-style codes (e.g. "#SWSH284"). */
    grid-template-columns: 64px minmax(0, 1fr) 100px minmax(120px, auto) 64px 24px;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    cursor: pointer;
    transition: background 0.15s;
    min-height: 40px;
    position: relative;
}
.card-list-row:last-child { border-bottom: none; }
.card-list-row:hover { background: rgba(255, 255, 255, 0.06); }
.card-list-row:focus-visible {
    outline: 2px solid rgba(102, 126, 234, 0.6);
    outline-offset: -2px;
}
.card-list-row.all-collected { background: rgba(0, 255, 136, 0.07); opacity: 1; }
/* Left-edge accent bar marks a completed row without dimming its content. */
.card-list-row.all-collected::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: linear-gradient(180deg, #00ff88, #00cc6e);
}

.card-list-row .row-num {
    font-family: 'SF Mono', Menlo, monospace;
    font-size: 0.75rem;
    color: rgba(241, 241, 241, 0.7);
    white-space: nowrap;
    /* Clip rather than spill onto the name cell if a label exceeds the track. */
    overflow: hidden;
    text-overflow: ellipsis;
}
.card-list-row .row-name {
    position: relative;
    font-size: 0.85rem;
    font-weight: 500;
    color: #f1f1f1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.card-list-row .row-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.card-list-row .row-rarity { display: flex; }
.card-list-row .row-rarity .rarity-badge {
    font-size: 0.6rem;
    padding: 2px 6px;
    margin: 0;
}
.card-list-row .row-variants {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}
.card-list-row .row-variant-empty {
    color: rgba(241, 241, 241, 0.3);
    font-size: 0.75rem;
}
.card-list-row .row-price {
    text-align: right;
    font-size: 0.75rem;
}
.card-list-row .row-price .price-tag {
    margin-left: 0;
}
.card-list-row .row-status {
    display: flex;
    align-items: center;
    justify-content: center;
}
.row-status-icon { display: inline-flex; }
.row-status-icon svg { width: 14px; height: 14px; }
.row-status-lock svg { fill: #00ff88; opacity: 0.85; }
.row-status-partial svg { fill: rgba(102, 126, 234, 0.85); }
.row-status-empty { width: 14px; height: 14px; }

/* Inline checkboxes inside a row */
.row-variant-inline {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 12px;
    font-size: 0.7rem;
    cursor: pointer;
    transition: background 0.15s;
    user-select: none;
}
.row-variant-inline:hover { background: rgba(255, 255, 255, 0.1); }
.row-variant-inline.checked { background: rgba(0, 255, 136, 0.2); }
.row-variant-inline input { cursor: pointer; width: 12px; height: 12px; margin: 0; }
.row-variant-inline .row-variant-label { white-space: nowrap; }

/* "X/N collected" pill for 3+ variant cards — opens the modal. */
.row-variant-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    background: rgba(102, 126, 234, 0.18);
    border: 1px solid rgba(102, 126, 234, 0.4);
    border-radius: 12px;
    color: #f1f1f1;
    font-family: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.row-variant-pill:hover {
    background: rgba(102, 126, 234, 0.3);
    border-color: rgba(102, 126, 234, 0.6);
}
.row-variant-pill.full {
    background: rgba(0, 255, 136, 0.18);
    border-color: rgba(0, 255, 136, 0.4);
}

/* Desktop hover popover — thumbnail of the card. Hidden on touch devices and
 * mobile widths where there's no hover concept. CSS-only — uses the existing
 * <img onerror> fallback to hide on load failure. */
.row-thumb-popover {
    position: absolute;
    left: 0;
    top: 100%;
    margin-top: 4px;
    padding: 4px;
    background: #16213e;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
    z-index: 50;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
}
.row-thumb-popover img {
    display: block;
    width: 140px;
    height: auto;
    border-radius: 4px;
}
@media (hover: hover) and (pointer: fine) {
    .card-list-row:hover .row-name .row-thumb-popover {
        opacity: 1;
    }
}
.card-list-row:nth-last-child(-n+3) .row-thumb-popover {
    top: auto;
    bottom: 100%;
    margin: 0 0 4px 0;
}

@media (max-width: 768px) {
    .view-toggle-btn { padding: 5px 10px; font-size: 0.7rem; }
    .view-toggle-btn span { display: none; }
    .card-list-row {
        /* rarity + price are display:none here, so only num · name · variants ·
         * status occupy tracks. Name takes the remaining width — the num track
         * is tightened and the variant pills strip their decorative icon
         * (below) so long names get as much room as possible. */
        grid-template-columns: 42px minmax(0, 1fr) auto 18px;
        gap: 6px;
        padding: 6px 10px;
        min-height: 44px;
    }
    .card-list-row .row-rarity { display: none; }
    .card-list-row .row-price { display: none; }
    .card-list-row .row-num { font-size: 0.7rem; }
    .card-list-row .row-name { font-size: 0.8rem; }
    .card-list-row .row-bulk-select { margin-right: 0; }
    .card-list-row .bulk-select-checkbox { width: 18px; height: 18px; }
    .card-list-row .row-variants { gap: 4px; }
    /* Drop the decorative emoji inside inline variant pills — the word label
     * ("Regular" / "Reverse Holo" / "Collected") carries the meaning and the
     * icon just costs width the card name needs more. */
    .row-variant-inline .row-variant-label span[aria-hidden="true"] { display: none; }
    .row-variant-inline { padding: 5px 7px; font-size: 0.65rem; min-height: 30px; gap: 3px; }
    .row-variant-inline input { width: 13px; height: 13px; }
    .row-variant-pill { padding: 5px 10px; font-size: 0.7rem; min-height: 30px; }
    .row-thumb-popover { display: none; }
}

/* Guest mode keeps inline toggles visible (read-only writes are routed through
 * requireSignIn). The view toggle itself is always available — guests can
 * still flip view mode locally via localStorage. */

.card-item,
.card {
    background: rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    padding: 8px;
    transition: all 0.2s;
    font-size: 0.85rem;
    min-width: 0;
    overflow: hidden;
    cursor: pointer;
}

.card-item:hover,
.card:hover {
    background: rgba(255, 255, 255, 0.12);
    transform: translateY(-1px);
}

/* Completed cards stay full-color/opacity; a brighter accent border + soft
   glow + a bottom "✓ COMPLETE" bar mark the state instead of dimming. */
.card-item.all-collected,
.card.completed {
    position: relative;
    background: rgba(0, 255, 136, 0.08);
    border: 1px solid rgba(0, 255, 136, 0.45);
    box-shadow: 0 0 8px rgba(0, 255, 136, 0.15);
    /* Grid tiles stretch to the tallest card in their row (align-items:
       stretch). Lay completed tiles out as a flex column and push the
       variants section to the bottom so the lock + "✓ COMPLETE" bar stay
       anchored to the tile's bottom edge even when the card's own content
       is shorter than its row-mates (e.g. single-variant EX cards). */
    display: flex;
    flex-direction: column;
}

.card-item.all-collected .variants-section,
.card.completed .variants-section {
    margin-top: auto;
}

/* Bottom "✓ COMPLETE" bar — normal-flow pseudo-element so it sits at the
   tile's bottom edge, after the variant checkboxes, never over the image. */
.card-item.all-collected::after,
.card.completed::after {
    content: "✓ COMPLETE";
    display: block;
    margin: 6px -8px -8px;
    padding: 4px 0;
    text-align: center;
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #14180a;
    text-shadow: 0 1px 1px rgba(255, 255, 255, 0.25);
    background: linear-gradient(90deg,
        #ff6b9d 0%, #c084fc 25%, #22d3ee 50%, #d4ff5b 75%, #ff6b9d 100%);
    background-size: 300% 100%;
    animation: holo-shimmer 6s linear infinite;
}

/* Lock badge on completed cards — icon-only padlock (the bar carries the
   label; this purely signals the soft-lock guarding the checkboxes). */
.completed-lock {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #00ff88;
    opacity: 1;
    margin-top: 4px;
}

.completed-lock svg {
    width: 15px;
    height: 15px;
    fill: #00ff88;
}

/* Inline confirm-on-collect chip (PR2 — replaces the legacy unlock-toast).
   Single horizontal pill anchored bottom-center; floats above the card modal
   (z-index 10001) when the user opens the chip from inside the modal. */
.collect-confirm-chip {
    position: fixed;
    left: 50%;
    bottom: calc(20px + env(safe-area-inset-bottom));
    transform: translateX(-50%) translateY(20px);
    opacity: 0;
    /* Bug 2 — explicitly assert pointer-events on the chip and its
       interactive children so a chip stays tappable even when overlaid by
       (or overlaying) the card modal. The chip lives at z-index 10001 above
       the modal's 10000 backdrop; without these explicit `auto` declarations
       a future ancestor with `pointer-events: none` could silently swallow
       taps on the Confirm / Cancel / +/- controls. */
    pointer-events: auto;
    background: rgba(20, 25, 50, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 215, 0, 0.25);
    border-radius: 14px;
    padding: 10px 14px;
    display: flex;
    align-items: center;
    gap: 14px;
    z-index: 10001;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    max-width: min(560px, calc(100vw - 24px));
    transition: opacity 220ms cubic-bezier(0.2, 0.9, 0.3, 1),
                transform 220ms cubic-bezier(0.2, 0.9, 0.3, 1),
                border-color 180ms ease;
    color: #f1f1f1;
}

.collect-confirm-chip.visible {
    transform: translateX(-50%) translateY(0);
    opacity: 1;
}

.collect-confirm-chip[data-state="dismissing"] {
    transform: translateX(-50%) translateY(20px);
    opacity: 0;
    transition: opacity 180ms ease-in, transform 180ms ease-in;
}

.collect-confirm-chip[data-state="error"] {
    border-color: #e74c3c;
    box-shadow: 0 8px 32px rgba(231, 76, 60, 0.35);
}

.collect-confirm-chip[data-mode="uncheck"] .collect-confirm-action {
    background: rgba(231, 76, 60, 0.85);
}
.collect-confirm-chip[data-mode="uncheck"] .collect-confirm-action:hover {
    background: rgba(231, 76, 60, 1);
}

.collect-confirm-identity {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.collect-confirm-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.collect-confirm-meta {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.72);
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.collect-confirm-variant {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    text-transform: capitalize;
}

.collect-confirm-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    pointer-events: auto;
}

.collect-confirm-stepper {
    display: flex;
    align-items: center;
    gap: 6px;
    background: rgba(255, 255, 255, 0.06);
    border-radius: 10px;
    padding: 2px;
}

.collect-confirm-stepper .sealed-qty-btn.collect-confirm-step {
    width: 44px;
    height: 44px;
    border-radius: 8px;
    font-size: 1.3rem;
}

.collect-confirm-qty {
    min-width: 28px;
    text-align: center;
    font-size: 1rem;
    font-weight: 700;
    color: #fff;
    transition: transform 120ms ease;
    display: inline-block;
}
.collect-confirm-qty.qty-bump {
    transform: scale(1.08);
}

.collect-confirm-btn {
    height: 44px;
    min-width: 88px;
    padding: 0 16px;
    border: none;
    border-radius: 10px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, opacity 0.15s;
    color: #fff;
    pointer-events: auto;
}

.collect-confirm-cancel {
    background: rgba(255, 255, 255, 0.1);
}
.collect-confirm-cancel:hover {
    background: rgba(255, 255, 255, 0.18);
}

.collect-confirm-action {
    background: #2ecc71;
    color: #0a1020;
}
.collect-confirm-action:hover {
    background: #27ae60;
}
.collect-confirm-action:disabled,
.collect-confirm-action.is-loading {
    opacity: 0.7;
    cursor: progress;
}
.collect-confirm-action.is-loading::after {
    content: '';
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-left: 8px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    vertical-align: middle;
    animation: collect-confirm-spin 0.8s linear infinite;
}

@keyframes collect-confirm-spin {
    to { transform: rotate(360deg); }
}

.collect-confirm-chip:focus-within {
    border-color: rgba(255, 215, 0, 0.55);
}

.collect-confirm-action:focus-visible,
.collect-confirm-cancel:focus-visible,
.collect-confirm-step:focus-visible {
    outline: 2px solid #ffd700;
    outline-offset: 2px;
}

@media (max-width: 559px) {
    .collect-confirm-chip {
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
        max-width: calc(100vw - 16px);
    }
    .collect-confirm-controls {
        justify-content: space-between;
    }
    .collect-confirm-btn {
        flex: 1 1 auto;
        min-width: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .sync-indicator.syncing,
    .sf-spinner,
    .scan-spinner {
        animation: none;
    }
    .collect-confirm-chip,
    .collect-confirm-chip[data-state="dismissing"] {
        transition: opacity 100ms ease;
        transform: translateX(-50%);
    }
    .collect-confirm-chip.visible {
        transform: translateX(-50%);
    }
    .collect-confirm-qty {
        transition: none;
    }
    .collect-confirm-action.is-loading::after {
        animation: none;
    }
    .collect-confirm-receipt {
        transition: opacity 100ms ease;
        transform: translateX(-50%);
    }
    .collect-confirm-receipt.visible {
        transform: translateX(-50%);
    }
}

/* When the card modal is open, push its bottom padding so the variant row
   stays reachable above the chip. PR3 owns the modal markup; this rule is
   the only modal-side coordination point. */
body.collect-confirm-active .card-modal {
    padding-bottom: 110px;
}

/* Receipt toast — small "Saved <name> +N" confirmation that slides in below
   the chip when the user rapid-taps another card. */
.collect-confirm-receipt {
    position: fixed;
    left: 50%;
    bottom: calc(20px + env(safe-area-inset-bottom));
    transform: translateX(-50%) translateY(80px);
    opacity: 0;
    background: rgba(46, 204, 113, 0.95);
    color: #0a1020;
    border-radius: 999px;
    padding: 8px 14px;
    font-size: 0.85rem;
    font-weight: 600;
    z-index: 10000;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
    transition: opacity 200ms ease, transform 200ms ease;
    pointer-events: none;
}
.collect-confirm-receipt.visible {
    transform: translateX(-50%) translateY(-72px);
    opacity: 1;
}

/* Single-tap silent commit + undo toast (10s with-action variant). Reuses the
   `.collect-confirm-receipt` base shape but switches to a flex container with
   an inline Undo button. Pointer events are re-enabled here because the user
   needs to click Undo. */
.collect-confirm-receipt.with-action {
    /* Override base green to dark so message + Undo button meet WCAG 1.4.3
       4.5:1 contrast. Base `.collect-confirm-receipt` background is green
       (rgba(46,204,113,0.95)), which made `#4a9eff` Undo on green ≈ 2.0:1 and
       `var(--accent-green)` message effectively invisible. */
    background: rgba(20, 25, 50, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 215, 0, 0.25);
    padding: 8px 8px 8px 16px;
    min-width: 280px;
    max-width: 420px;
    display: flex;
    align-items: center;
    gap: 12px;
    pointer-events: auto;
}
/* Single-card layout needs more horizontal room for [✓][name][−][N][+][Undo]. */
.collect-confirm-receipt.with-action.with-stepper {
    max-width: 480px;
    gap: 8px;
}
.collect-confirm-receipt.with-action .collect-confirm-receipt-message {
    color: #5fe599; /* light green on dark — ~10:1 */
}
.collect-confirm-receipt-icon {
    color: #5fe599;
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1;
}
.collect-confirm-receipt-name {
    flex: 1 1 auto;
    color: #5fe599;
    font-weight: 600;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    min-width: 0;
}
.collect-confirm-step-btn {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(255, 255, 255, 0.08);
    color: #f1f1f1;
    font-size: 1.2rem;
    font-weight: 600;
    line-height: 1;
    padding: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}
.collect-confirm-step-btn:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(0, 255, 136, 0.45);
}
.collect-confirm-step-btn:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}
.collect-confirm-step-btn:active {
    transform: translateY(1px);
}
.collect-confirm-step-value {
    min-width: 28px;
    text-align: center;
    font-weight: 700;
    color: #5fe599;
    font-variant-numeric: tabular-nums;
    flex: 0 0 auto;
}
.collect-confirm-receipt-message {
    flex: 1;
    color: var(--accent-green, #2fb46a);
    font-weight: 600;
}
.collect-confirm-receipt-undo {
    background: none;
    border: 1px solid rgba(74, 158, 255, 0.55);
    color: #7fb8ff; /* lighter blue on dark — ~7:1 */
    padding: 10px 16px;
    border-radius: 8px;
    cursor: pointer;
    min-width: 64px;
    min-height: 44px;
    font-weight: 600;
}
.collect-confirm-receipt-undo:hover {
    background: rgba(74, 158, 255, 0.12);
    border-color: rgba(74, 158, 255, 0.75);
}
.collect-confirm-receipt-undo:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}
@media (max-width: 480px) {
    .collect-confirm-receipt-meta { display: none; }
}
@media (max-width: 360px) {
    .collect-confirm-receipt.with-action {
        min-width: calc(100vw - 32px);
    }
    .collect-confirm-receipt.with-action.with-stepper {
        flex-wrap: wrap;
    }
}
body.collect-undo-active .card-modal {
    padding-bottom: 60px;
}
@media (prefers-reduced-motion: reduce) {
    .collect-confirm-receipt.with-action {
        transition: opacity 80ms ease;
        transform: translateX(-50%) !important;
    }
    .collect-confirm-receipt.with-action.visible {
        transform: translateX(-50%) !important;
    }
}

/* Card Detail Modal */
.card-modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.85);
    z-index: 10000;
    align-items: center;
    justify-content: center;
    padding: 20px;
    opacity: 0;
    transition: opacity 0.3s ease;
    /* Make the overscroll/momentum stop here so iOS can't keep scrolling the
     * underlying page through the overlay and intermittently swallow taps on
     * the close button. */
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
}

/* Lock body scroll while the card modal is open. iOS Safari ignores
 * `overflow: hidden` for momentum scrolling — pinning body with
 * position:fixed is the only reliable way to stop the underlying page
 * from intercepting taps on the close button. JS sets `top: -<scrollY>px`
 * inline so the visual position doesn't jump, and restores scroll on
 * close. `overscroll-behavior: contain` on the modal itself stops
 * bounce-scroll from leaking back to body. */
body.card-modal-open {
    overflow: hidden;
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
}

.card-modal.visible {
    display: flex;
    opacity: 1;
}

.card-modal-content {
    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 16px;
    max-width: 800px;
    width: 100%;
    max-height: 90vh;
    overflow-y: auto;
    position: relative;
    box-shadow: 0 10px 50px rgba(0, 0, 0, 0.5);
    transform: scale(0.9);
    transition: transform 0.3s ease;
    touch-action: pan-y pinch-zoom;
    overscroll-behavior: contain;
}

/* Tap-window guard — during the ~50ms window when openCardModal is being
 * called from a re-render handler (toggleVariantFromModal, modalQtyIncrement,
 * etc.), inbound taps land on partially-destroyed DOM and feel unresponsive.
 * Block them at the CSS layer; the JS clears data-rerendering once the new
 * DOM is in place. */
.card-modal-content[data-rerendering="true"] {
    pointer-events: none;
}

.card-modal.visible .card-modal-content {
    transform: scale(1);
}

.card-modal-close {
    position: absolute;
    top: 16px;
    right: 16px;
    background: rgba(255, 255, 255, 0.1);
    border: none;
    color: #f1f1f1;
    font-size: 1.5rem;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s;
    z-index: 10;
}

.card-modal-close:hover {
    background: rgba(255, 68, 68, 0.8);
    transform: rotate(90deg);
}

.card-modal-body {
    display: flex;
    gap: 24px;
    padding: 24px;
}

.card-modal-image {
    flex-shrink: 0;
    width: 300px;
}

.card-modal-image img {
    width: 100%;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}

.card-modal-details {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.card-modal-title {
    font-size: 1.5rem;
    font-weight: 700;
    color: #f1f1f1;
    margin-bottom: 4px;
}

.card-modal-number {
    font-size: 0.9rem;
    color: rgba(255, 255, 255, 0.6);
    font-weight: 600;
}

.card-modal-set {
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.5);
    margin-top: 4px;
}

.card-modal-rarity {
    display: inline-block;
    padding: 6px 12px;
    border-radius: 6px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-top: 8px;
}

.card-modal-variants {
    margin-top: 8px;
}

.card-modal-variants-title {
    font-size: 0.85rem;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.7);
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: 12px;
}

.card-modal-variant-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.card-modal-variant-item {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    font-size: 0.85rem;
}

.card-modal-variant-item.collected {
    background: rgba(0, 255, 136, 0.1);
    border-color: rgba(0, 255, 136, 0.3);
}

.card-modal-variant-checkbox {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

/* PR3 — modal owned + graded count pills (sit next to .card-modal-rarity).
 * Mirrors the gold pill grammar of .card-graded-badge but rendered inline
 * inside the modal header, side-by-side, so neither displaces the other. */
.card-modal-owned-badge,
.card-modal-graded-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    margin-top: 8px;
    margin-left: 6px;
    border-radius: 11px;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.02em;
    text-transform: lowercase;
    border: 1px solid rgba(0, 0, 0, 0.4);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    vertical-align: middle;
}
.card-modal-owned-badge {
    color: #0d3a1f;
    background: linear-gradient(135deg, #8aeab1 0%, #2fb46a 100%);
}
.card-modal-graded-badge {
    color: #1a1a1a;
    background: linear-gradient(135deg, #f5d57a 0%, #d4a017 100%);
}

/* PR3 — per-variant quantity stepper inside the card-modal variant rows.
 * Sits on its own line under the [checkbox] [label] [price] row so we don't
 * push the price off-screen at iPhone-SE width (320px). */
.modal-qty-stepper {
    flex-basis: 100%;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 6px;
}
.modal-qty-btn {
    width: 44px;
    height: 44px;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.35);
    background: rgba(255, 255, 255, 0.08);
    color: #f1f1f1;
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1;
    padding: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, border-color 0.15s;
}
.modal-qty-btn:hover {
    background: rgba(255, 255, 255, 0.16);
    border-color: rgba(0, 255, 136, 0.45);
}
.modal-qty-btn:focus-visible {
    background: rgba(255, 255, 255, 0.16);
    box-shadow: 0 0 0 2px #00ff88;
    outline: none;
}
.modal-qty-btn:active {
    transform: translateY(1px);
}
.modal-qty-value {
    min-width: 28px;
    text-align: center;
    font-size: 1rem;
    font-weight: 700;
    color: #00ff88;
}

/* Mobile responsive modal */
@media (max-width: 768px) {
    .card-modal-body {
        flex-direction: column;
        padding: 16px;
    }

    .card-modal-image {
        width: 100%;
        max-width: 280px;
        margin: 0 auto;
    }

    .card-modal-title {
        font-size: 1.2rem;
    }

    .card-modal-close {
        top: 12px;
        right: 12px;
        /* WCAG 2.1 AA minimum tap-target is 44x44. The previous 32x32 made the
         * X easy to miss on phones, which is part of why the overlay felt
         * unresponsive on mobile. */
        width: 44px;
        height: 44px;
        font-size: 1.4rem;
        /* Stay above modal content even if a child element grows a stacking
         * context, and make sure taps are never absorbed by a sibling. */
        z-index: 20;
        pointer-events: auto;
    }
}

/* Responsive design for block and set buttons */
@media (max-width: 768px) {
    .set-buttons {
        grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
        gap: 8px;
    }
    .set-btn { padding: 10px 8px; }
    .set-btn-logo-wrapper { height: 60px; }
    .set-btn-logo { max-height: 100%; }
    .set-btn-name { font-size: 0.8rem; }
}

/* Card image support */
.card-img-wrapper {
    width: 100%;
    aspect-ratio: 3 / 4;
    border-radius: 6px;
    overflow: hidden;
    margin-bottom: 6px;
    background: rgba(255, 255, 255, 0.04);
    position: relative;
}
.card-img-wrapper img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 0.3s ease;
}
.card-item:hover .card-img-wrapper img,
.card:hover .card-img-wrapper img {
    transform: scale(1.03);
}
.card-img-wrapper .card-img-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.65rem;
    opacity: 0.3;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.card-header {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: flex-start;
    gap: 8px;
}

.card-info {
    flex: 1;
    min-width: 0;
}

.tcgplayer-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    background: #2563eb;
    color: white;
    border-radius: 4px;
    text-decoration: none;
    transition: background 0.2s ease;
    flex-shrink: 0;
}

.tcgplayer-link:hover {
    background: #1d4ed8;
}

.tcgplayer-link svg {
    width: 16px;
    height: 16px;
}

.card-number {
    font-size: 0.7rem;
    opacity: 0.6;
    margin-bottom: 2px;
}

.card-name {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 3px;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rarity-badge {
    display: inline-block;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
}

/* Main set rarities */
.rarity-common { background: #666; }
.rarity-uncommon { background: #4a9eff; }
.rarity-rare { background: #9d4aff; }

/* EX and basic special */
.rarity-ex { background: #ff6b6b; }
.rarity-trainer { background: #ff9500; }
.rarity-energy { background: #48c774; }

/* Secret rare types (all get special styling) */
.rarity-secret { background: linear-gradient(45deg, #ffd700, #ffed4e); color: #000; }
.rarity-illustration-rare { 
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
}
.rarity-special-illustration-rare { 
    background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); 
}
.rarity-ultra-rare {
    background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.rarity-rare-holo-gx {
    background: linear-gradient(135deg, #00d2ff 0%, #3a7bd5 100%);
}
.rarity-hyper-rare { 
    background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); 
    color: #000;
}
.rarity-double-rare { 
    background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); 
}
.rarity-trainer-ultra-rare { 
    background: linear-gradient(135deg, #ff9a56 0%, #ffecd2 100%); 
    color: #000;
}
.rarity-gold-secret { 
    background: linear-gradient(135deg, #ffd89b 0%, #19547b 100%); 
}

/* Special mechanic rarities */
.rarity-ace-spec { 
    background: linear-gradient(135deg, #000000 0%, #434343 100%); 
    border: 2px solid #ffd700;
}
.rarity-radiant { 
    background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%); 
    color: #000;
}
.rarity-amazing-rare { 
    background: linear-gradient(135deg, #ee0979 0%, #ff6a00 100%); 
}
.rarity-shiny-rare {
    background: linear-gradient(135deg, #c0c0c0 0%, #ffffff 100%);
    color: #000;
}
.rarity-galarian-gallery {
    background: linear-gradient(135deg, #6366f1 0%, #ec4899 100%);
}
.rarity-trainer-gallery {
    background: linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%);
}

/* One-time announcement banner for sets whose totalCards denominator
 * changed when parallel-gallery sub-sets were added. Sits above
 * .card-controls inside .set-view-cards. Dismissed per-set via localStorage. */
.gallery-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    margin-bottom: 12px;
    background: linear-gradient(90deg, rgba(139, 92, 246, 0.16), rgba(99, 102, 241, 0.16));
    border: 1px solid rgba(139, 92, 246, 0.32);
    border-radius: 8px;
    color: #f1f1f1;
    font-size: 0.9rem;
}
.gallery-banner-text {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
}
.gallery-banner-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #a78bfa;
    box-shadow: 0 0 6px rgba(167, 139, 250, 0.7);
    flex-shrink: 0;
}
.gallery-banner-dismiss {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.2);
    color: #f1f1f1;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.15s ease;
}
.gallery-banner-dismiss:hover {
    background: rgba(255, 255, 255, 0.08);
}
.gallery-banner-dismiss:focus-visible {
    outline: 2px solid #a78bfa;
    outline-offset: 1px;
}
@media (max-width: 768px) {
    .gallery-banner { font-size: 0.82rem; padding: 8px 10px; }
}
.rarity-promo {
    background: linear-gradient(135deg, #ff512f 0%, #dd2476 100%);
}
.rarity-rare-holo {
    background: linear-gradient(135deg, #a855f7 0%, #7c3aed 100%);
}

/* Lorcana-specific rarities */
.rarity-super-rare {
    background: linear-gradient(135deg, #c084fc 0%, #a855f7 100%);
}
.rarity-legendary {
    background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
    color: #000;
}
.rarity-enchanted {
    background: linear-gradient(135deg, #c084fc 0%, #ec4899 50%, #f59e0b 100%);
}
.rarity-epic {
    background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%);
}
.rarity-iconic {
    background: linear-gradient(135deg, #fcd34d 0%, #fbbf24 30%, #ffffff 50%, #fbbf24 70%, #f59e0b 100%);
    color: #000;
}
.rarity-special {
    background: linear-gradient(135deg, #a855f7 0%, #ec4899 100%);
}

.region-badge {
    display: inline-block;
    background: #e74c3c;
    color: #fff;
    font-size: 0.55rem;
    font-weight: 700;
    padding: 1px 4px;
    border-radius: 3px;
    vertical-align: middle;
    margin-left: 4px;
}

/* Language sub-tab toggle for custom sets with mixed EN/JP cards */
.lang-toggle {
    display: flex;
    gap: 2px;
    margin: 0 auto 12px auto;
    background: rgba(0, 0, 0, 0.25);
    border-radius: 8px;
    padding: 3px;
    width: fit-content;
}

.lang-toggle-btn {
    padding: 6px 16px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: rgba(241, 241, 241, 0.45);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    gap: 6px;
}

.lang-toggle-btn:hover {
    color: rgba(241, 241, 241, 0.7);
    background: rgba(255, 255, 255, 0.05);
}

.lang-toggle-btn.active {
    background: rgba(255, 255, 255, 0.12);
    color: #f1f1f1;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

.lang-toggle-btn .lang-count {
    font-size: 0.65rem;
    opacity: 0.6;
    font-weight: 400;
}

.lang-toggle-btn.active .lang-count {
    opacity: 0.8;
}

.card-origin {
    font-size: 0.6rem;
    opacity: 0.45;
    padding: 2px 8px 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.variants-section {
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    padding-top: 6px;
}

.variants-title {
    font-size: 0.65rem;
    opacity: 0.5;
    margin-bottom: 4px;
    text-transform: uppercase;
    display: none; /* Hide "VARIANTS:" label to save space */
}

.variant-checkboxes {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.variant-checkbox {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 3px 6px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    font-size: 0.7rem;
    cursor: pointer;
    transition: all 0.2s;
}

.variant-checkbox:hover {
    background: rgba(255, 255, 255, 0.1);
}

.variant-checkbox.checked {
    background: rgba(0, 255, 136, 0.2);
}

.variant-checkbox input {
    cursor: pointer;
    width: 14px;
    height: 14px;
}

.variant-checkbox label {
    font-size: 0.7rem;
    flex: 1;
}

.variant-tcgplayer-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 2px;
    color: #888;
    text-decoration: none;
    transition: all 0.2s;
    border-radius: 3px;
    margin-left: auto;
}

.variant-tcgplayer-link:hover {
    color: #4a9eff;
    background: rgba(74, 158, 255, 0.1);
}

.variant-tcgplayer-link svg {
    display: block;
}

.single-variant {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 4px 6px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.7rem;
}

.single-variant.checked {
    background: rgba(0, 255, 136, 0.2);
}

.single-variant input {
    width: 14px;
    height: 14px;
}

/* Modal */
.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.9);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10000;
    padding: 20px;
}

.modal-content {
    background: #16213e;
    padding: 30px;
    border-radius: 15px;
    max-width: 400px;
    width: 100%;
}

.modal-title {
    font-size: 1.3rem;
    margin-bottom: 10px;
    color: #00ff88;
}

.modal-text {
    margin-bottom: 20px;
    opacity: 0.9;
    line-height: 1.5;
}

.modal-input {
    width: 100%;
    padding: 12px;
    border: 2px solid rgba(255, 255, 255, 0.2);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.05);
    color: #f1f1f1;
    font-size: 1rem;
    margin-bottom: 15px;
}

.modal-input:focus {
    outline: none;
    border-color: #00ff88;
}

.modal-buttons {
    display: flex;
    gap: 10px;
}

.modal-btn {
    flex: 1;
    padding: 12px;
    border: none;
    border-radius: 8px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
}

.modal-btn.primary {
    background: linear-gradient(135deg, #00ff88, #00d4ff);
    color: #000;
}

.modal-btn.primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 15px rgba(0, 255, 136, 0.4);
}

.error-text {
    color: #ff4444;
    font-size: 0.85rem;
    margin-top: 5px;
}

/* ── Auth modal ─────────────────────────────────────────────── */
.auth-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.92);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10001;
    padding: 20px;
}

.auth-modal-content {
    background: #16213e;
    padding: 30px;
    border-radius: 15px;
    max-width: 400px;
    width: 100%;
}

.auth-modal-title {
    font-size: 1.3rem;
    margin-bottom: 10px;
    color: #00ff88;
}

.auth-modal-text {
    margin-bottom: 20px;
    opacity: 0.9;
    line-height: 1.5;
}

.auth-input {
    width: 100%;
    padding: 12px;
    border: 2px solid rgba(255, 255, 255, 0.2);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.05);
    color: #f1f1f1;
    font-size: 1rem;
    margin-bottom: 12px;
}

.auth-input:focus {
    outline: none;
    border-color: #00ff88;
}

.auth-error {
    color: #ff4444;
    font-size: 0.85rem;
    min-height: 1.2em;
    margin-bottom: 8px;
}

.auth-buttons {
    display: flex;
    gap: 10px;
    margin-bottom: 12px;
}

.auth-btn {
    flex: 1;
    padding: 12px;
    border: 1px solid rgba(255,255,255,0.2);
    border-radius: 8px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    background: transparent;
    color: #f1f1f1;
}

.auth-btn.primary {
    background: linear-gradient(135deg, #00ff88, #00d4ff);
    color: #000;
    border: none;
}

.auth-btn.primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 15px rgba(0, 255, 136, 0.4);
}

.auth-btn.google {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: #fff;
    color: #333;
    border: none;
    margin-bottom: 12px;
}

.auth-btn.google:hover {
    background: #f0f0f0;
}

.auth-links {
    display: flex;
    justify-content: space-between;
    font-size: 0.85rem;
}

.auth-links a {
    color: #00d4ff;
    text-decoration: none;
}

.auth-links a:hover {
    text-decoration: underline;
}

/* ── User header bar ────────────────────────────────────────── */
.user-bar {
    display: none;
    align-items: center;
    justify-content: space-between;
    padding: 8px 16px;
    background: rgba(0, 255, 136, 0.08);
    border-radius: 10px;
    margin-bottom: 12px;
    font-size: 0.9rem;
    flex-wrap: wrap;
    gap: 8px;
}

.user-bar-left {
    display: flex;
    align-items: center;
    gap: 10px;
}

.user-display-name {
    font-weight: 600;
    color: #00ff88;
}

.user-collection-name {
    opacity: 0.7;
    font-size: 0.85rem;
}

.user-bar-right {
    display: flex;
    align-items: center;
    gap: 8px;
}

.user-bar-btn {
    background: none;
    border: 1px solid rgba(255,255,255,0.15);
    color: #f1f1f1;
    padding: 5px 12px;
    border-radius: 6px;
    font-size: 0.8rem;
    cursor: pointer;
    transition: all 0.2s;
}

.user-bar-btn:hover {
    background: rgba(255,255,255,0.1);
}

.user-bar-btn.gear {
    padding: 5px 8px;
    font-size: 1rem;
}

/* ── Theme picker (Settings popover) ─────────────────────────────
 * Story 1 of the Holofoil adoption. Lives inside .user-bar-right.
 * The button is a small chip with a half-moon glyph; clicking it
 * opens a popover with two theme options. State is owned by
 * js/theme.js; this file is presentation only. */
.theme-toggle-wrap {
    position: relative;
    display: inline-block;
}
.user-bar-btn.theme-toggle-btn {
    padding: 5px 9px;
    font-size: 1rem;
    line-height: 1;
}
.user-bar-btn.theme-toggle-btn[aria-expanded="true"] {
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 215, 0, 0.4);
}
.theme-toggle-icon {
    display: inline-block;
    line-height: 1;
    transform: translateY(-1px);
}

.theme-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 240px;
    background: #1a1d35;
    border: 1px solid rgba(255, 215, 0, 0.25);
    border-radius: 10px;
    box-shadow:
        0 12px 32px rgba(0, 0, 0, 0.55),
        0 0 0 1px rgba(0, 0, 0, 0.2),
        inset 0 1px 0 rgba(255, 255, 255, 0.04);
    padding: 6px;
    z-index: 1000;
    opacity: 0;
    transform: translateY(-4px);
    pointer-events: none;
    transition: opacity 0.15s ease, transform 0.15s ease;
}
.theme-menu.open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.theme-menu-title {
    padding: 8px 10px 6px;
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.4px;
    color: rgba(241, 241, 241, 0.55);
}

.theme-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s ease;
    color: #f1f1f1;
    font-size: 0.86rem;
}
.theme-option:hover { background: rgba(255, 255, 255, 0.05); }
.theme-option:focus-within {
    background: rgba(255, 215, 0, 0.08);
    outline: 2px solid rgba(255, 215, 0, 0.55);
    outline-offset: -2px;
}
.theme-option input[type="radio"] {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin: 0;
    accent-color: #ffd700;
    cursor: pointer;
}
.theme-option-swatch {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 7px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.theme-swatch-scrapbook {
    background:
        radial-gradient(circle at 30% 30%, rgba(255, 215, 0, 0.85), transparent 60%),
        linear-gradient(135deg, #1a1a4e 0%, #2d1b69 50%, #1a3a5c 100%);
}
.theme-swatch-holofoil {
    background:
        radial-gradient(circle at 30% 30%, rgba(192, 132, 252, 0.8), transparent 55%),
        radial-gradient(circle at 70% 70%, rgba(34, 211, 238, 0.65), transparent 55%),
        linear-gradient(135deg, #07000f 0%, #2d0052 100%);
}
.theme-option-text {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
}
.theme-option-label {
    font-weight: 700;
    font-size: 0.86rem;
}
.theme-option-sub {
    font-size: 0.72rem;
    color: rgba(241, 241, 241, 0.5);
    margin-top: 2px;
}
.theme-menu-foot {
    padding: 8px 10px 4px;
    margin-top: 4px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
    font-size: 0.68rem;
    color: rgba(241, 241, 241, 0.35);
    font-style: italic;
}

/* Mobile — pin the popover to a viewport-relative slot just below the
 * user-bar so it stays centered horizontally instead of being
 * right-anchored to the toggle (which on narrow phones pushed the
 * 240px-wide menu off the left edge). The user-bar wraps to 2 rows on
 * mobile, so 96px from the top of the viewport puts the menu right
 * under the moon icon without overlapping it. */
@media (max-width: 767px) {
    .theme-menu {
        position: fixed !important;
        top: 96px !important;
        bottom: auto !important;
        left: 12px !important;
        right: 12px !important;
        min-width: 0 !important;
        max-width: none !important;
        max-height: calc(100vh - 108px);
        max-height: calc(100dvh - 108px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
}

@media (max-width: 767px) {
    .user-bar-right {
        flex-wrap: wrap;
        justify-content: flex-end;
    }
    .sync-status {
        font-size: 0.75rem;
        padding: 3px 8px;
    }
}

/* ── Invite banner ──────────────────────────────────────────── */
.invite-banner {
    position: fixed;
    top: -80px;
    left: 50%;
    transform: translateX(-50%);
    background: #16213e;
    border: 1px solid #00ff88;
    border-radius: 10px;
    padding: 12px 20px;
    display: flex;
    align-items: center;
    gap: 16px;
    z-index: 9999;
    transition: top 0.3s ease;
    max-width: 500px;
    width: 90%;
    box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}

.invite-banner.visible {
    top: 16px;
}

.invite-banner-text {
    flex: 1;
    font-size: 0.9rem;
    line-height: 1.3;
}

.invite-banner-actions {
    display: flex;
    gap: 6px;
}

.invite-btn {
    padding: 6px 14px;
    border: none;
    border-radius: 6px;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.invite-btn.accept {
    background: #00ff88;
    color: #000;
}

.invite-btn.decline {
    background: rgba(255,255,255,0.1);
    color: #f1f1f1;
}

/* ── Collection switcher panel ──────────────────────────────── */
.collection-panel {
    position: fixed;
    top: 0;
    right: -350px;
    width: 340px;
    height: 100%;
    background: #16213e;
    z-index: 10002;
    transition: right 0.3s ease;
    box-shadow: -4px 0 20px rgba(0,0,0,0.5);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}

.collection-panel.open {
    right: 0;
}

.collection-panel-header {
    padding: 20px;
    border-bottom: 1px solid rgba(255,255,255,0.1);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.collection-panel-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: #00ff88;
}

.collection-panel-close {
    background: none;
    border: none;
    color: #f1f1f1;
    font-size: 1.5rem;
    cursor: pointer;
}

.collection-panel-body {
    padding: 16px 20px;
    flex: 1;
}

.collection-list-item {
    padding: 12px;
    border-radius: 8px;
    cursor: pointer;
    margin-bottom: 8px;
    border: 1px solid rgba(255,255,255,0.08);
    transition: background 0.15s;
}

.collection-list-item:hover {
    background: rgba(255,255,255,0.05);
}

.collection-list-item.active {
    border-color: #00ff88;
    background: rgba(0, 255, 136, 0.08);
}

.collection-list-item-name {
    font-weight: 600;
    margin-bottom: 2px;
}

.collection-list-item-role {
    font-size: 0.75rem;
    opacity: 0.6;
}

.collection-panel-actions {
    padding: 16px 20px;
    border-top: 1px solid rgba(255,255,255,0.1);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.collection-action-btn {
    padding: 10px;
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 8px;
    background: transparent;
    color: #f1f1f1;
    font-size: 0.9rem;
    cursor: pointer;
    text-align: left;
    transition: background 0.15s;
}

.collection-action-btn:hover {
    background: rgba(255,255,255,0.08);
}

.collection-panel-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    z-index: 10001;
}

.collection-panel-overlay.open {
    display: block;
}

@media (max-width: 768px) {
    h1 { font-size: 1.3rem; }
    .header-logo { width: min(300px, 80vw); }
    .header-pokemon-bg .pokemon-pikachu { width: 58px; right: 3px; }
    .header-pokemon-bg .pokemon-psyduck { width: 52px; left: 3px; }
    .header-pokemon-bg .pokemon-togepi { width: 42px; }
    .header-pokemon-bg .pokeball-accent { display: none; }
    .card-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: 4px;
    }
    .sealed-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
    }
    .set-buttons { grid-template-columns: 1fr; }
    .card-item,
    .card {
        padding: 5px;
        font-size: 0.75rem;
    }
    .card-name {
        font-size: 0.75rem;
    }
    .card-number {
        font-size: 0.65rem;
    }
    .rarity-badge {
        font-size: 0.55rem;
        padding: 1px 4px;
    }
    .variant-checkbox {
        padding: 2px 4px;
        font-size: 0.65rem;
    }
    .variant-checkbox label {
        font-size: 0.6rem;
    }
    .variant-checkbox input {
        width: 12px;
        height: 12px;
    }
    .card-controls {
        flex-direction: column;
        gap: 8px;
    }
    .filter-buttons {
        width: 100%;
        justify-content: center;
    }
    .rarity-filters {
        gap: 4px;
        justify-content: center;
    }
    .rarity-btn {
        padding: 3px 8px;
        font-size: 0.6rem;
    }
    .filter-btn {
        padding: 6px 12px;
        font-size: 0.75rem;
    }
    .search-container {
        max-width: 100%;
    }
    .search-input {
        font-size: 0.8rem;
        padding: 6px 32px 6px 10px;
    }
}

/* Price tags on card grid */
.price-tag {
    display: none;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 0.6rem;
    font-weight: 700;
    background: rgba(0, 200, 83, 0.25);
    color: #69f0ae;
    margin-left: 4px;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.price-tag.loaded {
    display: inline-block;
    opacity: 1;
}

/* "N/A" state — pricing source returned no data for this card. Muted color
   so it visibly differs from a real $ price without disappearing. */
.price-tag.na {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.55);
}

/* Market price in card modal */
.card-modal-price {
    margin-top: 8px;
    padding: 8px 12px;
    background: rgba(0, 200, 83, 0.1);
    border: 1px solid rgba(0, 200, 83, 0.25);
    border-radius: 8px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.card-modal-price.na {
    background: rgba(255, 255, 255, 0.04);
    border-color: rgba(255, 255, 255, 0.12);
}

.modal-price-label {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.6);
    font-weight: 600;
}

.modal-price-value {
    font-size: 1rem;
    font-weight: 700;
    color: #69f0ae;
}

.card-modal-price.na .modal-price-value {
    color: rgba(255, 255, 255, 0.55);
}

/* Per-variant price next to each variant checkbox in the card modal */
.card-modal-variant-price {
    margin-left: auto;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 700;
    background: rgba(0, 200, 83, 0.2);
    color: #69f0ae;
    white-space: nowrap;
}

.card-modal-variant-price.na {
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.5);
}

/* Collection value in set buttons */
.set-btn-value {
    font-size: 0.65rem;
    color: #69f0ae;
    margin-top: 4px;
    font-weight: 600;
    opacity: 0.8;
}

.set-btn-value.na {
    color: rgba(255, 255, 255, 0.55);
}

/* Footer Styles */
.app-footer {
    background: rgba(0, 0, 0, 0.3);
    color: rgba(255, 255, 255, 0.6);
    padding: 12px 20px;
    margin-top: 40px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    font-size: 0.75rem;
    text-align: center;
}

.footer-content {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 8px;
}

.footer-text {
    color: rgba(255, 255, 255, 0.5);
}

.footer-separator {
    color: rgba(255, 255, 255, 0.3);
}

.footer-link {
    color: rgba(100, 181, 246, 0.8);
    text-decoration: none;
    transition: color 0.2s;
}

.footer-link:hover {
    color: #64b5f6;
    text-decoration: underline;
}

@media (max-width: 768px) {
    .app-footer {
        padding: 10px 15px;
        font-size: 0.7rem;
    }
}

/* ===== Store Hunter ===== */

.sf-search-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    padding: 12px;
    background: rgba(0, 0, 0, 0.3);
    border-radius: 12px;
    margin-bottom: 12px;
}

.sf-locate-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 16px;
    background: linear-gradient(135deg, #2563eb, #1d4ed8);
    color: #fff;
    border: none;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
}

.sf-locate-btn:hover {
    filter: brightness(1.15);
    transform: translateY(-1px);
}

.sf-address-wrap {
    display: flex;
    flex: 1;
    min-width: 200px;
    gap: 0;
}

.sf-address-input {
    flex: 1;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-right: none;
    border-radius: 8px 0 0 8px;
    color: #f1f1f1;
    font-size: 0.85rem;
    transition: all 0.2s;
}

.sf-address-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

.sf-address-input:focus {
    outline: none;
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(37, 99, 235, 0.5);
}

.sf-address-search-btn {
    padding: 10px 18px;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 0 8px 8px 0;
    color: #f1f1f1;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
}

.sf-address-search-btn:hover {
    background: rgba(255, 255, 255, 0.18);
}

.sf-radius-wrap {
    display: flex;
    align-items: center;
    gap: 6px;
    color: rgba(255, 255, 255, 0.7);
    font-size: 0.85rem;
}

.sf-radius-select {
    padding: 8px 10px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    color: #f1f1f1;
    font-size: 0.85rem;
    cursor: pointer;
}

.sf-status-msg {
    padding: 10px 14px;
    border-radius: 8px;
    font-size: 0.85rem;
    margin-bottom: 12px;
}

.sf-status-error {
    background: rgba(255, 68, 68, 0.15);
    border: 1px solid rgba(255, 68, 68, 0.3);
    color: #ff8888;
}

.sf-status-info {
    background: rgba(37, 99, 235, 0.15);
    border: 1px solid rgba(37, 99, 235, 0.3);
    color: #93bbfc;
}

.sf-map-wrap {
    position: relative;
    margin-bottom: 12px;
}

.sf-map {
    height: 420px;
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.1);
    z-index: 1;
}

.sf-loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.6);
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    color: #f1f1f1;
    font-size: 0.9rem;
    z-index: 2;
}

.sf-spinner {
    width: 24px;
    height: 24px;
    border: 3px solid rgba(255, 255, 255, 0.2);
    border-top-color: #2563eb;
    border-radius: 50%;
    animation: sf-spin 0.8s linear infinite;
}

@keyframes sf-spin {
    to { transform: rotate(360deg); }
}

.sf-list-panel {
    background: rgba(0, 0, 0, 0.2);
    border-radius: 12px;
    border: 1px solid rgba(255, 255, 255, 0.06);
    overflow: hidden;
}

.sf-list-header {
    padding: 14px 16px;
    font-size: 0.9rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.7);
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.sf-store-list {
    max-height: 420px;
    overflow-y: auto;
}

.sf-store-item {
    padding: 12px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.04);
    cursor: pointer;
    transition: background 0.15s;
}

.sf-store-item:hover {
    background: rgba(255, 255, 255, 0.05);
}

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

.sf-store-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
}

.sf-store-name {
    font-size: 0.9rem;
    font-weight: 600;
    color: #f1f1f1;
}

.sf-store-dist {
    font-size: 0.75rem;
    font-weight: 700;
    color: #3b82f6;
    white-space: nowrap;
    padding: 2px 8px;
    background: rgba(37, 99, 235, 0.15);
    border-radius: 10px;
}

.sf-store-addr {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.5);
    margin-top: 4px;
}

.sf-store-hours {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.4);
    margin-top: 2px;
}

/* Store links */
.sf-store-links {
    display: flex;
    gap: 8px;
    margin-top: 6px;
}

.sf-store-link {
    font-size: 0.75rem;
    color: rgba(100, 181, 246, 0.8);
    text-decoration: none;
    transition: color 0.2s;
}

.sf-store-link:hover {
    color: #64b5f6;
    text-decoration: underline;
}

/* Popup links */
.sf-popup-links {
    margin-top: 6px;
    font-size: 0.8rem;
}

.sf-popup-links a {
    color: #2563eb;
    text-decoration: none;
}

.sf-popup-links a:hover {
    text-decoration: underline;
}

/* Disclaimer */
.sf-disclaimer {
    text-align: center;
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.35);
    padding: 10px 16px;
    font-style: italic;
}

/* Leaflet popup overrides */
.sf-popup-name {
    font-weight: 700;
    font-size: 0.9rem;
    margin-bottom: 4px;
}

.sf-popup-addr,
.sf-popup-hours {
    font-size: 0.8rem;
    color: #555;
}

.sf-popup-dist {
    font-size: 0.78rem;
    color: #2563eb;
    font-weight: 600;
    margin-top: 2px;
}

/* ===== Pokemon Symbol Identifier ===== */

.si-search-bar {
    margin-bottom: 10px;
}

.si-search-input {
    width: 100%;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 10px;
    color: #f1f1f1;
    font-size: 0.85rem;
    box-sizing: border-box;
    transition: all 0.2s;
}

.si-search-input::placeholder {
    color: rgba(255, 255, 255, 0.4);
}

.si-search-input:focus {
    outline: none;
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(37, 99, 235, 0.5);
}

.si-description {
    font-size: 0.78rem;
    color: rgba(255, 255, 255, 0.45);
    margin-bottom: 16px;
    font-style: italic;
}

/* Loading / error / empty states */
.si-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 48px 16px;
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.9rem;
}

.si-error,
.si-empty {
    text-align: center;
    padding: 48px 16px;
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.9rem;
}

.si-error {
    color: #ff8888;
}

/* Series group */
.si-series-group {
    margin-bottom: 18px;
}

.si-series-header {
    font-size: 0.82rem;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.6);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 6px 10px;
    margin-bottom: 8px;
    background: rgba(255, 255, 255, 0.04);
    border-radius: 6px;
    border-left: 3px solid #2563eb;
}

/* Symbol grid */
.si-symbol-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 8px;
}

.si-symbol-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 10px 6px 8px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 8px;
    transition: all 0.15s;
    cursor: default;
}

.si-symbol-item:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.12);
    transform: translateY(-1px);
}

.si-symbol-img-wrap {
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 6px;
}

.si-symbol-img {
    max-width: 40px;
    max-height: 40px;
    object-fit: contain;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
}

.si-symbol-code {
    font-size: 0.8rem;
    font-weight: 800;
    color: #93bbfc;
    text-transform: uppercase;
    letter-spacing: 1px;
    text-align: center;
    line-height: 40px;
}

.si-symbol-name {
    font-size: 0.7rem;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.85);
    text-align: center;
    line-height: 1.2;
    word-break: break-word;
}

.si-symbol-year {
    font-size: 0.62rem;
    color: rgba(255, 255, 255, 0.35);
    margin-top: 2px;
}

/* Mobile overrides */
@media (max-width: 767px) {
    .sf-search-bar {
        flex-direction: column;
        align-items: stretch;
    }

    .sf-locate-btn {
        justify-content: center;
    }

    .sf-address-wrap {
        min-width: unset;
    }

    .sf-map {
        height: 300px;
    }

    .si-symbol-grid {
        grid-template-columns: repeat(auto-fill, minmax(85px, 1fr));
        gap: 6px;
    }

    .si-symbol-img-wrap {
        width: 34px;
        height: 34px;
    }

    .si-symbol-img {
        max-width: 34px;
        max-height: 34px;
    }

    .si-symbol-name {
        font-size: 0.65rem;
    }
}

/* ── Custom Set Editor Modal ──────────────────────────────────── */
.cse-modal {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: rgba(0,0,0,0.7);
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.2s;
    padding: 16px;
}
.cse-modal.open { opacity: 1; }

.cse-modal-content {
    background: #1a1a2e;
    border-radius: 16px;
    width: 100%;
    max-width: 720px;
    max-height: 90vh;
    overflow-y: auto;
    border: 1px solid rgba(255,255,255,0.1);
}

.cse-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    border-bottom: 1px solid rgba(255,255,255,0.1);
}
.cse-modal-header h2 {
    margin: 0;
    font-size: 1.1rem;
    color: #fff;
}
.cse-close {
    background: none;
    border: none;
    color: #aaa;
    font-size: 1.5rem;
    cursor: pointer;
    padding: 0 4px;
}
.cse-close:hover { color: #fff; }

.cse-modal-body { padding: 20px; }

.cse-step { display: none; }
.cse-step.active { display: block; }

.cse-form-group {
    margin-bottom: 14px;
}
.cse-form-group label {
    display: block;
    font-size: 0.85rem;
    color: #aaa;
    margin-bottom: 4px;
}
.cse-form-row {
    display: flex;
    gap: 12px;
}
.cse-form-row .cse-form-group { flex: 1; }

.cse-input {
    width: 100%;
    padding: 8px 10px;
    background: rgba(255,255,255,0.08);
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 8px;
    color: #fff;
    font-size: 0.9rem;
    box-sizing: border-box;
}
.cse-input:focus {
    outline: none;
    border-color: #2563eb;
}
.cse-textarea {
    min-height: 60px;
    resize: vertical;
}
.cse-color-input {
    width: 48px;
    height: 36px;
    padding: 2px;
    border-radius: 6px;
    cursor: pointer;
}
.cse-tags-hint {
    margin-top: 5px;
    font-size: 0.72rem;
    color: rgba(255, 255, 255, 0.5);
}

/* Epic #497 Story 2 — Manage Categories modal rows */
.csc-error {
    margin-bottom: 12px;
    padding: 8px 10px;
    border-radius: 8px;
    background: rgba(220, 38, 38, 0.15);
    border: 1px solid rgba(220, 38, 38, 0.4);
    color: #fca5a5;
    font-size: 0.85rem;
}
.csc-empty {
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.85rem;
    padding: 12px 0;
}
.csc-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
/* Reorder chevrons sit at the LEFT of the row (a reorder-handle position),
   before the label — keeping them out of the already-full right-side actions
   cluster so they never overflow on mobile. */
.csc-row-reorder {
    display: flex;
    flex-direction: column;
    gap: 1px;
    flex-shrink: 0;
}
.csc-move-btn {
    width: 24px;
    height: 14px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 4px;
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.55rem;
    line-height: 1;
    cursor: pointer;
}
.csc-move-btn:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
}
.csc-move-btn:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 1px;
}
.csc-move-btn:disabled {
    opacity: 0.3;
    cursor: default;
}
.csc-row-label {
    color: #fff;
    font-size: 0.95rem;
    font-weight: 600;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.csc-row-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}
.csc-row-actions .cse-btn {
    padding: 6px 12px;
    font-size: 0.8rem;
}
/* Destructive action reads as recessive, not equal to Assign/Rename. */
.csc-row-actions .csc-delete {
    color: #ff8a8a;
}
/* Narrow viewports: drop the action buttons to a full-width second line so
   three buttons + a long tag name never overflow the row. */
@media (max-width: 420px) {
    .csc-row {
        flex-wrap: wrap;
        gap: 6px;
    }
    .csc-row-actions {
        width: 100%;
    }
    .csc-row-actions .cse-btn {
        flex: 1;
    }
    /* Give the stacked reorder chevrons an accessible tap target on touch
       (WCAG 2.5.8) — 14px tall is too small to hit reliably on a phone. */
    .csc-move-btn {
        width: 30px;
        height: 22px;
    }
}
/* Keyboard focus ring for modal buttons (covers the editor too). */
.cse-btn:focus-visible,
.cse-close:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}
.csc-assign-hint {
    color: rgba(255, 255, 255, 0.6);
    font-size: 0.85rem;
    margin-bottom: 12px;
}
.csc-assign-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    cursor: pointer;
}
.csc-assign-name {
    color: #fff;
    font-size: 0.9rem;
}
.csc-assign-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 16px;
}
/* Story 4 — New category create flow + personal-category list marker. */
.csc-new-cat {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.csc-new-name-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 12px;
}
.csc-new-label {
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.8rem;
    font-weight: 600;
}
.csc-new-scope {
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    padding: 10px 12px;
    margin: 0 0 12px;
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
.csc-scope-opt {
    color: #fff;
    font-size: 0.9rem;
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}
.csc-scope-hint {
    color: rgba(255, 255, 255, 0.5);
    font-size: 0.8rem;
}
.csc-row-personal .csc-row-label {
    display: inline-flex;
    align-items: center;
}
.cse-logo-input-row {
    display: flex;
    gap: 10px;
    align-items: center;
}
.cse-logo-input-row .cse-input { flex: 1; }
.cse-logo-preview {
    width: 40px;
    height: 40px;
    border-radius: 6px;
    overflow: hidden;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.6rem;
    color: #888;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.1);
}
.cse-logo-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.cse-btn {
    padding: 10px 20px;
    border: none;
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s;
}
.cse-btn.primary {
    background: #2563eb;
    color: #fff;
    width: 100%;
    margin-top: 10px;
}
.cse-btn.primary:hover { background: #1d4fd8; }
.cse-btn.secondary {
    background: rgba(255,255,255,0.1);
    color: #ccc;
}
.cse-btn.secondary:hover { background: rgba(255,255,255,0.15); }

.cse-card-picker-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
}
.cse-selected-count {
    color: #00ff88;
    font-size: 0.9rem;
    font-weight: 600;
}

.cse-set-selector {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;
}
.cse-set-selector select { flex: 1.5; }
.cse-picker-search { flex: 1; }

.cse-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 8px;
    max-height: 45vh;
    overflow-y: auto;
    margin-bottom: 12px;
    padding: 4px;
}

.cse-picker-card {
    background: rgba(255,255,255,0.05);
    border: 2px solid transparent;
    border-radius: 8px;
    padding: 4px;
    cursor: pointer;
    transition: border-color 0.15s, transform 0.1s;
    text-align: center;
}
.cse-picker-card:hover {
    border-color: rgba(255,255,255,0.2);
    transform: scale(1.03);
}
.cse-picker-card.selected {
    border-color: #00ff88;
    background: rgba(0,255,136,0.08);
}

.cse-picker-card-img {
    aspect-ratio: 63/88;
    overflow: hidden;
    border-radius: 4px;
    margin-bottom: 4px;
}
.cse-picker-card-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.cse-picker-card-info {
    font-size: 0.7rem;
    color: #ccc;
    line-height: 1.2;
}
.cse-picker-card-name {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cse-picker-card-num {
    color: #888;
    font-size: 0.65rem;
}

/* ── Search/Browse Mode Tabs ─────────────────────────────────── */
.cse-mode-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 12px;
    background: rgba(255,255,255,0.05);
    border-radius: 8px;
    padding: 3px;
}
.cse-mode-tab {
    flex: 1;
    padding: 8px 12px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: #999;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.cse-mode-tab:hover { color: #ccc; }
.cse-mode-tab.active {
    background: #2563eb;
    color: #fff;
}

/* ── Global Search Input ─────────────────────────────────────── */
.cse-global-search {
    font-size: 1rem !important;
    padding: 12px 14px !important;
    min-height: 44px;
    margin-bottom: 8px;
}

.cse-search-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}
.cse-add-all-btn {
    background: #00c853;
    color: #000;
    font-weight: 700;
    padding: 8px 16px;
    border-radius: 8px;
    border: none;
    cursor: pointer;
    font-size: 0.85rem;
    transition: background 0.15s, opacity 0.15s;
    white-space: nowrap;
}
.cse-add-all-btn:hover { background: #00e676; }
.cse-add-all-btn:disabled {
    opacity: 0.4;
    cursor: default;
}
.cse-search-result-count {
    color: #888;
    font-size: 0.8rem;
}
.cse-search-hint {
    text-align: center;
    color: #666;
    font-size: 0.85rem;
    padding: 30px 10px;
}
.cse-no-results {
    text-align: center;
    color: #888;
    font-size: 0.85rem;
    padding: 30px 10px;
    grid-column: 1 / -1;
}

/* ── Card set origin label in search results ─────────────────── */
.cse-picker-card-set {
    display: block;
    color: #888;
    font-size: 0.6rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Selected Cards Panel ────────────────────────────────────── */
.cse-selected-panel {
    margin: 12px 0 4px;
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 8px;
    overflow: hidden;
}
.cse-selected-panel-toggle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: 10px 14px;
    background: rgba(255,255,255,0.05);
    border: none;
    color: #ccc;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}
.cse-selected-panel-toggle:hover { background: rgba(255,255,255,0.08); }
.cse-panel-arrow { font-size: 0.7rem; color: #888; }

.cse-selected-cards-list {
    display: none;
    max-height: 200px;
    overflow-y: auto;
    padding: 4px 0;
}
.cse-selected-empty {
    text-align: center;
    color: #666;
    font-size: 0.8rem;
    padding: 16px;
}
.cse-selected-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    font-size: 0.8rem;
}
.cse-selected-item:hover { background: rgba(255,255,255,0.03); }
.cse-selected-item-name {
    color: #ddd;
    font-weight: 500;
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cse-selected-item-origin {
    color: #777;
    font-size: 0.7rem;
    white-space: nowrap;
}
.cse-selected-item-remove {
    background: none;
    border: none;
    color: #666;
    font-size: 1.1rem;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
}
.cse-selected-item-remove:hover { color: #ff4444; }

/* ── Artwork Picker ──────────────────────────────────────────── */
.cse-artwork-toggle {
    width: 100%;
    margin-top: 6px;
    background: rgba(255,255,255,0.06) !important;
    color: #aaa !important;
    font-size: 0.8rem !important;
    padding: 8px 12px !important;
    font-weight: 500 !important;
}
.cse-artwork-toggle:hover {
    background: rgba(255,255,255,0.1) !important;
    color: #ddd !important;
}
.cse-artwork-picker {
    margin-top: 8px;
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 8px;
    padding: 10px;
    background: rgba(0,0,0,0.2);
}
.cse-artwork-picker .cse-input {
    margin-bottom: 8px;
}
.cse-artwork-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
    gap: 8px;
    max-height: 200px;
    overflow-y: auto;
}
.cse-artwork-item {
    text-align: center;
    cursor: pointer;
    padding: 6px;
    border: 2px solid transparent;
    border-radius: 8px;
    transition: border-color 0.15s, background 0.15s;
}
.cse-artwork-item:hover {
    border-color: rgba(255,255,255,0.2);
    background: rgba(255,255,255,0.03);
}
.cse-artwork-item.selected {
    border-color: #2563eb;
    background: rgba(37,99,235,0.1);
}
.cse-artwork-item img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: contain;
}
.cse-artwork-item span {
    display: block;
    font-size: 0.6rem;
    color: #aaa;
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cse-artwork-hint, .cse-artwork-loading {
    text-align: center;
    color: #666;
    font-size: 0.8rem;
    padding: 16px;
    grid-column: 1 / -1;
}

/* ── "+ New Set" button ───────────────────────────────────────── */
.new-set-btn,
.manage-categories-btn {
    border: 2px dashed rgba(255,255,255,0.2) !important;
    background: transparent !important;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100px;
    gap: 8px;
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
}
.new-set-btn:hover,
.manage-categories-btn:hover {
    border-color: rgba(255,255,255,0.4) !important;
    background: rgba(255,255,255,0.03) !important;
}
.new-set-btn-icon {
    font-size: 2rem;
    color: rgba(255,255,255,0.4);
    line-height: 1;
}

/* ── Edit/Delete action buttons on set buttons ───────────────── */
.custom-set-actions {
    display: flex;
    gap: 4px;
    justify-content: center;
    margin-top: 6px;
}
.custom-set-action-btn {
    background: rgba(255,255,255,0.08);
    border: none;
    border-radius: 4px;
    padding: 4px 6px;
    cursor: pointer;
    color: #aaa;
    transition: color 0.15s, background 0.15s;
    line-height: 1;
}
.custom-set-action-btn:hover {
    background: rgba(255,255,255,0.15);
    color: #fff;
}
.custom-set-action-btn:focus-visible {
    outline: 2px solid #4a9eff;
    outline-offset: 2px;
}
.custom-set-action-btn.delete:hover {
    color: #ff4444;
    background: rgba(255,68,68,0.1);
}
/* Epic #497 Story 5 — pin/archive toggles in the action cluster. */
.custom-set-action-btn.pin.active {
    color: #ffcb05;
    background: rgba(255,203,5,0.15);
}
.custom-set-action-btn.pin:hover {
    color: #ffcb05;
    background: rgba(255,203,5,0.12);
}
.custom-set-action-btn.archive.active {
    color: #6fb0ff;
    background: rgba(111,176,255,0.15);
}
.custom-set-action-btn.archive:hover {
    color: #6fb0ff;
    background: rgba(111,176,255,0.12);
}
/* Four action buttons now share the cluster — tighten the gap/padding at
   narrow widths so they don't overflow the tile (rail stabilized in #484/#492). */
@media (max-width: 767px) {
    .custom-set-actions { gap: 3px; }
    /* Keep an accessible touch target (~32px) for all four buttons even on a
       2-column mobile tile — 4*32 + 3*3 gap ≈ 137px fits the ~145px tile row. */
    .custom-set-action-btn {
        min-width: 32px;
        min-height: 32px;
        padding: 6px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

/* At-a-glance marker so a pinned set is recognizable while scrolling, not only
   by its (small) active star button. Keyed off the .pinned class on the tile. */
.set-btn.pinned {
    position: relative;
}
.set-btn.pinned::after {
    content: "";
    position: absolute;
    top: 7px;
    right: 7px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #ffcb05;
    box-shadow: 0 0 5px rgba(255, 203, 5, 0.7);
}

/* ── Mobile overrides for editor ─────────────────────────────── */
@media (max-width: 767px) {
    .cse-modal { padding: 8px; }
    .cse-modal-content { max-height: 95vh; }
    .cse-set-selector { flex-direction: column; }
    .cse-picker-grid {
        grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
        max-height: 40vh;
    }
    .cse-form-row { flex-direction: column; gap: 0; }
    .cse-artwork-grid {
        grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
    }
    .cse-mode-tab { font-size: 0.8rem; padding: 8px 8px; }
    .cse-selected-cards-list { max-height: 150px; }
}

/* ── Scanner entry points (Story 1.1) ─────────────────────── */
/* Floating action button — fixed bottom-right, shown only on collection tabs */
.scan-fab {
    position: fixed;
    bottom: 24px;
    right: 24px;
    z-index: 900;
    display: none;
    align-items: center;
    gap: 8px;
    padding: 14px 22px;
    background: linear-gradient(135deg, #ffd700 0%, #ff9500 100%);
    color: #1a1a2e;
    border: 2px solid rgba(255, 255, 255, 0.35);
    border-radius: 50px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.02em;
    cursor: pointer;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 215, 0, 0.4);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.scan-fab:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 215, 0, 0.6);
}
.scan-fab:active { transform: translateY(0); }
.scan-fab-icon { flex: 0 0 auto; }

/* Reveal the FAB on collection tabs (Pokemon / Lorcana / Custom Sets). */
body:has(#pokemon-tcg-content.active) .scan-fab,
body:has(#lorcana-content.active) .scan-fab,
body:has(#custom-sets-content.active) .scan-fab {
    display: inline-flex;
}

/* Per-set scan button (lives inside .card-controls) */
.set-scan-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    background: rgba(255, 215, 0, 0.15);
    color: #ffd700;
    border: 1px solid rgba(255, 215, 0, 0.4);
    border-radius: 6px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.set-scan-btn:hover {
    background: rgba(255, 215, 0, 0.25);
    border-color: rgba(255, 215, 0, 0.7);
}
.set-scan-btn:active { transform: translateY(1px); }
.set-scan-btn svg { flex: 0 0 auto; }

/* Scanner placeholder modal (real camera modal lands in Story 1.2) */
.scan-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.75);
    z-index: 10003;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.scan-modal.open { display: flex; }
.scan-modal-content {
    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
    border: 1px solid rgba(255, 215, 0, 0.3);
    border-radius: 12px;
    padding: 32px;
    max-width: 420px;
    width: 100%;
    text-align: center;
    position: relative;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
.scan-modal-close {
    position: absolute;
    top: 8px;
    right: 12px;
    background: none;
    border: none;
    color: #f1f1f1;
    font-size: 28px;
    line-height: 1;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.15s ease;
}
.scan-modal-close:hover { opacity: 1; }
.scan-modal-content h2 {
    color: #ffd700;
    margin-bottom: 12px;
    font-size: 22px;
}
.scan-modal-status {
    color: #f1f1f1;
    margin-bottom: 8px;
    font-size: 15px;
}
.scan-modal-scope {
    color: #a0a0c0;
    margin-bottom: 24px;
    font-size: 13px;
    font-style: italic;
    min-height: 1em;
}
.scan-modal-ok {
    background: linear-gradient(135deg, #ffd700 0%, #ff9500 100%);
    color: #1a1a2e;
    border: none;
    padding: 10px 28px;
    border-radius: 6px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
}

/* Camera stages (Story 1.2) */
.scan-modal.scan-camera-modal .scan-modal-content,
.scan-modal-content.scan-camera {
    max-width: 520px;
    padding: 24px 24px 28px;
    max-height: 92vh;
    overflow-y: auto;
}
.scan-stage { display: none; }
.scan-modal[data-stage="loading"] .scan-stage-loading { display: block; text-align: center; }
.scan-modal[data-stage="error"] .scan-stage-error { display: block; text-align: center; }
.scan-modal[data-stage="preview"] .scan-stage-preview { display: block; }
.scan-modal[data-stage="captured"] .scan-stage-captured { display: block; }
.scan-modal[data-stage="manual"] .scan-stage-manual { display: block; text-align: center; }
.scan-modal[data-stage="disambiguation"] .scan-stage-disambiguation { display: block; }
.scan-modal[data-stage="result"] .scan-stage-result { display: block; text-align: center; }
.scan-modal[data-stage="custom-picker"] .scan-stage-custom-picker { display: block; }
.scan-modal[data-stage="grade-picker"] .scan-stage-grade-picker { display: block; }
.scan-modal[data-stage="clip-carousel"] .scan-stage-clip-carousel { display: block; }
.scan-modal[data-stage="clip-bad-frame"] .scan-stage-clip-bad-frame { display: block; text-align: center; }

/* Scan result stage (Story 3.1) — shared shell for the matched card */
.scan-stage-result .scan-result-image {
    display: block;
    margin: 4px auto 14px;
    width: 100%;
    max-width: 260px;
    aspect-ratio: 5 / 7;
    object-fit: contain;
    background: #0a0a1a;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.12);
}
.scan-stage-result .scan-result-card-name {
    color: #f1f1f1;
    font-size: 18px;
    font-weight: 700;
    margin: 0 0 4px;
}
.scan-stage-result .scan-result-card-meta {
    color: #a0a0c0;
    font-size: 13px;
    margin: 0 0 12px;
}
.scan-stage-result .scan-result-price-slot {
    min-height: 24px;
    margin: 0 0 12px;
}
.scan-stage-result .scan-result-price-slot:empty { margin-bottom: 8px; }

/* Story 4.1 — TCGCSV price display */
.scan-stage-result .scan-result-price {
    display: inline-block;
    color: #f1f1f1;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: 0.01em;
}
.scan-stage-result .scan-result-price-loading {
    color: #a0a0c0;
    font-weight: 500;
    font-size: 13px;
}
.scan-stage-result .scan-result-price-empty {
    color: #a0a0c0;
    font-weight: 500;
}

/* Story 4.2 — Multi-variant price breakdown. */
.scan-stage-result .scan-result-price-variants {
    display: block;
    font-size: 14px;
    font-weight: 500;
}
.scan-stage-result .scan-result-price-variant-list {
    list-style: none;
    margin: 0 0 4px;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.scan-stage-result .scan-result-price-variant-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
}
.scan-stage-result .scan-result-price-variant-label {
    color: #a0a0c0;
    font-weight: 500;
}
.scan-stage-result .scan-result-price-variant-value {
    color: #f1f1f1;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.scan-stage-result .scan-result-price-variant-value.scan-result-price-empty {
    color: #a0a0c0;
    font-weight: 500;
}
.scan-stage-result .scan-result-price-source {
    display: block;
    color: #a0a0c0;
    font-size: 12px;
    font-weight: 500;
    margin-top: 2px;
}

/* Story 4.3 — "No pricing available" graceful empty state */
.scan-stage-result .scan-result-no-price {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    color: #e0e0ff;
}
.scan-stage-result .scan-result-no-price-msg {
    margin: 0;
    color: #a0a0c0;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.01em;
}
.scan-stage-result .scan-result-no-price-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    justify-content: center;
}
.scan-stage-result .scan-result-no-price-refresh {
    padding: 6px 14px;
    font-size: 13px;
    font-weight: 700;
    color: #f1f1f1;
    background: rgba(96, 109, 247, 0.28);
    border: 1px solid rgba(96, 109, 247, 0.6);
    border-radius: 6px;
    cursor: pointer;
}
.scan-stage-result .scan-result-no-price-refresh:hover {
    background: rgba(96, 109, 247, 0.42);
}
.scan-stage-result .scan-result-no-price-link {
    font-size: 13px;
    font-weight: 600;
    color: #a9b4ff;
    text-decoration: underline;
}
.scan-stage-result .scan-result-no-price-link:hover {
    color: #c9d1ff;
}
.scan-stage-result .scan-result-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 0 14px;
    min-height: 0;
}
.scan-stage-result .scan-result-actions:empty { margin-bottom: 4px; }
.scan-stage-result .scan-actions { margin-top: 4px; }

/* Mark in set action + In-collection badge (Story 3.2) */
.scan-stage-result .scan-result-mark-btn {
    align-self: stretch;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.scan-stage-result .scan-result-badge {
    display: inline-block;
    align-self: center;
    margin-top: 2px;
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 700;
    color: #22cc77;
    background: rgba(34, 204, 119, 0.12);
    border: 1px solid rgba(34, 204, 119, 0.35);
    border-radius: 999px;
    letter-spacing: 0.02em;
}
.scan-stage-result .scan-result-badge[hidden] { display: none; }
.scan-stage-result[data-collected="true"] .scan-result-mark-btn {
    background: transparent;
    color: #f1f1f1;
    border: 1px solid rgba(255, 255, 255, 0.3);
}

.scan-manual-note { color: #e0e0ff; font-size: 15px; font-weight: 600; margin: 8px 0 12px; }
.scan-manual-placeholder { color: #a0a0c0; font-size: 13px; margin: 0 0 18px; }

.scan-manual-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    text-align: left;
    margin: 0 auto 4px;
    max-width: 380px;
}
.scan-manual-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 13px;
    color: #e0e0ff;
    font-weight: 600;
}
.scan-manual-field > span { font-size: 12px; color: #a0a0c0; text-transform: uppercase; letter-spacing: 0.04em; }
.scan-manual-field select,
.scan-manual-field input {
    font-family: inherit;
    font-size: 14px;
    padding: 9px 10px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(0, 0, 0, 0.35);
    color: #f1f1f1;
}
.scan-manual-field select:focus,
.scan-manual-field input:focus {
    outline: none;
    border-color: rgba(255, 215, 0, 0.7);
}
.scan-manual-error {
    color: #ff8080;
    font-size: 13px;
    margin: 0;
    min-height: 1em;
}
.scan-manual-error:empty { min-height: 0; }
.scan-stage-manual .scan-actions { margin-top: 6px; }

/* Disambiguation list (Story 2.5) */
.scan-disambig-title {
    color: #e0e0ff;
    font-size: 16px;
    font-weight: 700;
    margin: 8px 0 14px;
    text-align: center;
}
.scan-disambig-list {
    list-style: none;
    padding: 0;
    margin: 0 0 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 60vh;
    overflow-y: auto;
}
.scan-disambig-list li {
    margin: 0;
    padding: 0;
}
.scan-disambig-item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    color: #f1f1f1;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.scan-disambig-item:hover,
.scan-disambig-item:focus-visible {
    background: rgba(255, 215, 0, 0.08);
    border-color: rgba(255, 215, 0, 0.55);
    outline: none;
}
.scan-disambig-item:active { transform: translateY(1px); }
.scan-disambig-thumb {
    width: 48px;
    height: 67px;
    flex-shrink: 0;
    background: #0a0a1a;
    border-radius: 4px;
    object-fit: cover;
    display: block;
}
.scan-disambig-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.scan-disambig-card-name {
    font-size: 14px;
    font-weight: 700;
    color: #f1f1f1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.scan-disambig-set-name {
    font-size: 12px;
    color: #a0a0c0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.scan-disambig-confidence {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    padding: 4px 8px;
    border-radius: 999px;
    background: rgba(255, 215, 0, 0.18);
    color: #ffd700;
    border: 1px solid rgba(255, 215, 0, 0.35);
    white-space: nowrap;
}

/* CLIP carousel (Story 3.3) — top-3 matches shown side-by-side on desktop,
   horizontally swipeable on mobile. Pre-focused candidate gets a yellow ring
   so a confident scan is one tap. Score badges are color-coded so the user
   has a quick read on confidence: green ≥80, yellow 60–79, red <60. */
.scan-clip-title {
    color: #e0e0ff;
    font-size: 16px;
    font-weight: 700;
    margin: 8px 0 14px;
    text-align: center;
}
.scan-clip-carousel {
    display: flex;
    flex-direction: row;
    gap: 10px;
    margin: 0 0 16px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    padding: 4px 2px 8px;
}
.scan-clip-card {
    flex: 1 1 0;
    min-width: 130px;
    max-width: 180px;
    scroll-snap-align: center;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px;
    background: rgba(255, 255, 255, 0.04);
    border: 2px solid rgba(255, 255, 255, 0.12);
    border-radius: 10px;
    color: #f1f1f1;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.scan-clip-card:hover,
.scan-clip-card:focus-visible {
    background: rgba(255, 215, 0, 0.08);
    border-color: rgba(255, 215, 0, 0.55);
    outline: none;
}
.scan-clip-card:active { transform: translateY(1px); }
.scan-clip-card.is-focused {
    border-color: #ffd700;
    background: rgba(255, 215, 0, 0.12);
    box-shadow: 0 0 0 2px rgba(255, 215, 0, 0.35);
}
.scan-clip-card-thumb {
    width: 100%;
    aspect-ratio: 5 / 7;
    background: #0a0a1a;
    border-radius: 6px;
    object-fit: contain;
    display: block;
}
.scan-clip-card-name {
    font-size: 13px;
    font-weight: 700;
    color: #f1f1f1;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.scan-clip-card-meta {
    font-size: 11px;
    color: #a0a0c0;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.scan-clip-card-score {
    align-self: flex-start;
    font-size: 11px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.2);
}
.scan-clip-card-score[data-conf="high"] {
    background: rgba(46, 204, 113, 0.18);
    color: #4cd483;
    border-color: rgba(46, 204, 113, 0.45);
}
.scan-clip-card-score[data-conf="med"] {
    background: rgba(255, 215, 0, 0.18);
    color: #ffd700;
    border-color: rgba(255, 215, 0, 0.45);
}
.scan-clip-card-score[data-conf="low"] {
    background: rgba(231, 76, 60, 0.18);
    color: #f08070;
    border-color: rgba(231, 76, 60, 0.45);
}
.scan-clip-bad-frame-message {
    color: #f1f1f1;
    font-size: 14px;
    line-height: 1.4;
    margin: 12px 0 16px;
}
@media (max-width: 480px) {
    .scan-clip-carousel { gap: 8px; }
    .scan-clip-card { min-width: 120px; }
}

/* Custom-set picker (Story 3.3) — list of user's custom sets with a per-row
   "Add here" button. Visual language mirrors the disambiguation list above. */
.scan-picker-title {
    color: #e0e0ff;
    font-size: 16px;
    font-weight: 700;
    margin: 8px 0 14px;
    text-align: center;
}
.scan-picker-list {
    list-style: none;
    padding: 0;
    margin: 0 0 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 60vh;
    overflow-y: auto;
}
.scan-picker-list li {
    margin: 0;
    padding: 0;
}
.scan-picker-item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    color: #f1f1f1;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.scan-picker-item:hover,
.scan-picker-item:focus-visible {
    background: rgba(255, 215, 0, 0.08);
    border-color: rgba(255, 215, 0, 0.55);
    outline: none;
}
.scan-picker-item:active { transform: translateY(1px); }
.scan-picker-logo {
    width: 48px;
    height: 48px;
    flex-shrink: 0;
    background: #0a0a1a;
    border-radius: 6px;
    object-fit: contain;
    display: block;
    padding: 4px;
}
.scan-picker-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.scan-picker-set-name {
    font-size: 14px;
    font-weight: 700;
    color: #f1f1f1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.scan-picker-cta {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 700;
    padding: 6px 10px;
    border-radius: 6px;
    background: rgba(255, 215, 0, 0.18);
    color: #ffd700;
    border: 1px solid rgba(255, 215, 0, 0.35);
    white-space: nowrap;
}
.scan-picker-empty {
    color: #a0a0c0;
    font-size: 13px;
    text-align: center;
    padding: 16px 8px;
    margin: 0;
}

/* Story 5.2 — grade picker */
.scan-grade-title {
    color: #e0e0ff;
    font-size: 16px;
    font-weight: 700;
    margin: 8px 0 14px;
    text-align: center;
}
.scan-grade-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    text-align: left;
    margin: 0 auto 4px;
    max-width: 380px;
}
.scan-grade-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 13px;
    color: #e0e0ff;
    font-weight: 600;
}
.scan-grade-field > span {
    font-size: 12px;
    color: #a0a0c0;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.scan-grade-company-buttons {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
}
.scan-grade-company-btn {
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    padding: 8px 6px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(0, 0, 0, 0.35);
    color: #f1f1f1;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.scan-grade-company-btn:hover,
.scan-grade-company-btn:focus-visible {
    border-color: rgba(255, 215, 0, 0.55);
    outline: none;
}
.scan-grade-company-btn.active {
    background: rgba(255, 215, 0, 0.18);
    border-color: rgba(255, 215, 0, 0.7);
    color: #ffd700;
}
.scan-grade-field input {
    font-family: inherit;
    font-size: 14px;
    padding: 9px 10px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(0, 0, 0, 0.35);
    color: #f1f1f1;
}
.scan-grade-field input:focus {
    outline: none;
    border-color: rgba(255, 215, 0, 0.7);
}
.scan-grade-error {
    color: #ff8080;
    font-size: 13px;
    margin: 0;
    min-height: 1em;
}
.scan-grade-error:empty { min-height: 0; }
.scan-stage-grade-picker .scan-actions { margin-top: 6px; }

/* Card-modal graded instances list (Story 5.2) */
.graded-instances-section {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.graded-instances-title {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #a0a0c0;
    margin: 0 0 8px;
}
.graded-instances-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.graded-instance-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 6px;
}
.graded-instance-label {
    flex: 1;
    font-size: 13px;
    font-weight: 700;
    color: #ffd700;
}
.graded-instance-cert {
    font-size: 11px;
    color: #a0a0c0;
    font-weight: 400;
    margin-left: 6px;
}
.graded-instance-btn {
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    padding: 4px 8px;
    border-radius: 4px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(0, 0, 0, 0.3);
    color: #f1f1f1;
    cursor: pointer;
}
.graded-instance-btn:hover,
.graded-instance-btn:focus-visible {
    border-color: rgba(255, 215, 0, 0.55);
    outline: none;
}
.graded-instance-btn.graded-instance-remove {
    color: #ff8080;
}

.scan-spinner {
    width: 36px;
    height: 36px;
    border: 3px solid rgba(255, 215, 0, 0.25);
    border-top-color: #ffd700;
    border-radius: 50%;
    margin: 12px auto 16px;
    animation: scan-spin 0.8s linear infinite;
}
@keyframes scan-spin { to { transform: rotate(360deg); } }

.scan-error-message {
    color: #ff9090;
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 6px;
}
.scan-error-help {
    color: #a0a0c0;
    font-size: 13px;
    margin-bottom: 20px;
}

.scan-video-wrap {
    position: relative;
    width: 100%;
    aspect-ratio: 3 / 4;
    background: #000;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: 16px;
}
.scan-video-wrap video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* Bulk-mode toggle bar above the live preview. The toggle drives the
   "auto-add and keep scanning" behavior; the counter to the right shows
   how many cards have been added in this scanner session. */
.scan-bulk-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
    padding: 4px 2px;
}
.scan-bulk-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    user-select: none;
    font-size: 13px;
    font-weight: 600;
    color: rgba(241, 241, 241, 0.85);
}
.scan-bulk-toggle input {
    accent-color: rgba(255, 215, 0, 0.95);
    width: 16px;
    height: 16px;
    cursor: pointer;
}
.scan-bulk-count {
    font-size: 12px;
    font-weight: 700;
    color: rgba(80, 220, 120, 0.9);
    background: rgba(20, 90, 40, 0.25);
    padding: 3px 8px;
    border-radius: 999px;
}

/* Toast — the brief "✓ Added <card>" confirmation shown over the live
   preview when bulk mode auto-actions a successful scan. Fades in/out
   without interrupting the camera or the scan loop. */
.scan-toast {
    position: absolute;
    bottom: 16px;
    left: 50%;
    transform: translateX(-50%) translateY(8px);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: 999px;
    background: rgba(20, 90, 40, 0.92);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.01em;
    pointer-events: none;
    opacity: 0;
    transition: opacity 180ms ease, transform 180ms ease;
    max-width: calc(100% - 24px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
    z-index: 5;
}
.scan-toast.is-visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* Green flash overlay on bulk-add success — the camera frame briefly
   tints green so the user gets a peripheral confirmation. */
.scan-video-wrap.is-flash::after {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(80, 220, 120, 0.35);
    pointer-events: none;
    animation: scan-flash-fade 600ms ease-out forwards;
}
@keyframes scan-flash-fade {
    0% { opacity: 0.95; }
    100% { opacity: 0; }
}

/* Real-time scan status pill — floats above the live preview and shows the
   auto-scan loop's current stage (looking / reading / matching). */
.scan-status {
    position: absolute;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.65);
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    pointer-events: none;
    max-width: calc(100% - 24px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.scan-status-spinner {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    border: 2px solid rgba(255, 215, 0, 0.35);
    border-top-color: rgba(255, 215, 0, 1);
    animation: scan-status-spin 0.8s linear infinite;
    flex-shrink: 0;
}
.scan-status.is-found .scan-status-spinner {
    border: 2px solid rgba(80, 220, 120, 0.9);
    border-top-color: rgba(80, 220, 120, 0.9);
    animation: none;
}
.scan-status.is-found {
    background: rgba(20, 90, 40, 0.85);
}
@keyframes scan-status-spin {
    to { transform: rotate(360deg); }
}

/* Card-shaped framing overlay — standard TCG card ratio 63:88 (~0.716) */
.scan-card-frame {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 70%;
    aspect-ratio: 63 / 88;
    border: 2px dashed rgba(255, 215, 0, 0.9);
    border-radius: 8px;
    pointer-events: none;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.35);
}

.scan-actions {
    display: flex;
    gap: 10px;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
}
.scan-btn {
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    padding: 10px 20px;
    border-radius: 6px;
    cursor: pointer;
    transition: transform 0.1s ease, opacity 0.15s ease;
    border: 1px solid transparent;
}
.scan-btn:active { transform: translateY(1px); }
.scan-btn-primary {
    background: linear-gradient(135deg, #ffd700 0%, #ff9500 100%);
    color: #1a1a2e;
    border: none;
}
.scan-btn-secondary {
    background: transparent;
    color: #f1f1f1;
    border-color: rgba(255, 255, 255, 0.3);
}
.scan-btn-secondary:hover { border-color: rgba(255, 255, 255, 0.55); }
.scan-btn-link {
    background: transparent;
    color: rgba(241, 241, 241, 0.65);
    border: none;
    text-decoration: underline;
    padding: 6px 8px;
    font-size: 12px;
    font-weight: 600;
}
.scan-btn-link:hover { color: #fff; }
.scan-btn-switch {
    background: rgba(255, 215, 0, 0.15);
    color: #ffd700;
    border-color: rgba(255, 215, 0, 0.4);
    padding: 8px 12px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.scan-btn-switch:hover {
    background: rgba(255, 215, 0, 0.25);
    border-color: rgba(255, 215, 0, 0.7);
}
.scan-btn-switch[hidden] {
    display: none;
}

.scan-captured-wrap {
    position: relative;
    width: 100%;
    aspect-ratio: 3 / 4;
    background: #000;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* When identification is done (spinner hidden), show the status pill in a
   more prominent, wrap-friendly position at the bottom of the frozen frame
   so users can read the full failure reason without it being clipped. */
.scan-captured-wrap .scan-status {
    top: auto;
    bottom: 12px;
    left: 12px;
    right: 12px;
    transform: none;
    max-width: none;
    white-space: normal;
    text-align: left;
    line-height: 1.35;
}
.scan-captured-wrap .scan-status.is-idle .scan-status-spinner {
    display: none;
}
.scan-captured-wrap canvas {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

/* Diagnostics inline panel on the captured stage — shows what every
   signal source returned for the current scan, with a Copy button so
   the user can share the trace when results are wrong. */
.scan-diagnostics-panel {
    margin-top: 12px;
    background: rgba(10, 10, 12, 0.98);
    border: 1px solid rgba(255, 215, 0, 0.4);
    border-radius: 10px;
    padding: 10px 12px;
    font-size: 12px;
    color: #eee;
}
.scan-diagnostics-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
    font-size: 13px;
}
.scan-diagnostics-actions { display: flex; gap: 4px; }
.scan-diagnostics-content {
    margin: 0;
    padding: 8px;
    max-height: 220px;
    overflow: auto;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: 'SF Mono', Menlo, Consolas, monospace;
    font-size: 11px;
    line-height: 1.45;
    color: rgba(220, 220, 220, 0.92);
    background: rgba(0, 0, 0, 0.45);
    border-radius: 6px;
    -webkit-overflow-scrolling: touch;
}
.scan-captured-note {
    color: #a0a0c0;
    font-size: 13px;
    font-style: italic;
    margin-bottom: 16px;
    text-align: center;
}

@media (max-width: 767px) {
    .scan-fab {
        bottom: 16px;
        right: 16px;
        width: 56px;
        height: 56px;
        padding: 0;
        justify-content: center;
        border-radius: 50%;
    }
    .scan-fab-label { display: none; }
    .scan-modal-content { padding: 24px 20px; }
    .scan-modal-content.scan-camera { padding: 20px 16px 24px; }
    .scan-video-wrap, .scan-captured-wrap { aspect-ratio: 3 / 4; }
    .scan-btn { padding: 10px 16px; font-size: 13px; }
}

/* Story 5.3 — graded pricing link-out */
.graded-pricing-cell {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.graded-price-slot {
    display: inline-block;
    min-width: 48px;
    font-size: 13px;
    font-weight: 600;
    color: #e8e8f0;
    font-variant-numeric: tabular-nums;
    /* Reserved — populated in Story 5.6 (Phase 2). Ships empty. */
}
.graded-price-slot:empty::before {
    content: '—';
    color: rgba(255, 255, 255, 0.35);
    font-weight: 400;
}
.graded-comps-link {
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    padding: 6px 10px;
    border-radius: 5px;
    cursor: pointer;
    background: rgba(255, 215, 0, 0.12);
    color: #ffd700;
    border: 1px solid rgba(255, 215, 0, 0.4);
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}
.graded-comps-link:hover {
    background: rgba(255, 215, 0, 0.22);
    border-color: rgba(255, 215, 0, 0.7);
}
.graded-comps-link:focus-visible {
    outline: 2px solid #ffd700;
    outline-offset: 2px;
}
.graded-comps-link:active {
    transform: translateY(1px);
}

/* Story 5.4 — graded badge + modal graded-instances list */
.card-graded-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    color: #1a1a1a;
    background: linear-gradient(135deg, #f5d57a 0%, #d4a017 100%);
    border: 1px solid rgba(0, 0, 0, 0.4);
    border-radius: 11px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
    pointer-events: none;
    z-index: 3;
    letter-spacing: 0.02em;
}
/* Issue #391 — owned-count badge in grid + list views.
 * Green pill, count >= 2, locale-neutral "×N" format. Mirrors the modal's
 * .card-modal-owned-badge gradient so the visual vocabulary is consistent. */
.card-owned-badge {
    position: absolute;
    top: 6px;
    left: 6px;
    padding: 3px 7px;
    border-radius: 11px;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1;
    color: #0d3a1f;
    background: linear-gradient(135deg, #8aeab1 0%, #2fb46a 100%);
    border: 1px solid rgba(0, 0, 0, 0.35);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    pointer-events: none;
    z-index: 2;
    font-variant-numeric: tabular-nums;
}
.card-list-row .card-owned-badge {
    position: static;
    margin-right: 6px;
    vertical-align: middle;
}
.card-owned-badge.pulse { animation: owned-badge-pulse 250ms ease-out; }
@keyframes owned-badge-pulse {
    0% { transform: scale(1); }
    50% { transform: scale(1.15); }
    100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .card-owned-badge.pulse { animation: none; }
}

/* Issue #395 — bulk-edit selection mode. The bulk-select checkbox now lives
 * inside the card modal (one focused card at a time) instead of on every card
 * tile. The action bar reveals only when at least one card is selected. */
.bulk-select-checkbox {
    width: 24px;
    height: 24px;
    margin: 0;
    border-radius: 50%;
    accent-color: #2ecc71;
    cursor: pointer;
}
.bulk-select-checkbox.modal-context {
    width: 24px;
    height: 24px;
    margin: 0;
    background: transparent;
    box-shadow: none;
}
.card-modal-bulk-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    margin-bottom: 12px;
}
.card-modal-bulk-row label {
    color: #f1f1f1;
    font-weight: 500;
    cursor: pointer;
    user-select: none;
}
.bulk-select-checkbox:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}

/* "Select visible" pill in .card-controls (next to rarity filters). */
.bulk-select-all-visible {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.08);
    color: inherit;
    border: 1px solid rgba(255, 255, 255, 0.15);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    user-select: none;
}
.bulk-select-all-visible:hover {
    background: rgba(46, 204, 113, 0.15);
    border-color: rgba(46, 204, 113, 0.45);
}
.bulk-select-all-visible:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}

/* Viewport-bottom-fixed action bar. Mutually exclusive with chip + undo
 * toast — those modules clear their UI when bulk selection becomes
 * non-empty. Mirrors the chip's gold-on-navy palette so the visual
 * vocabulary is consistent. */
.bulk-action-bar {
    position: fixed;
    bottom: calc(20px + env(safe-area-inset-bottom));
    left: 50%;
    transform: translateX(-50%);
    background: rgba(20, 25, 50, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 215, 0, 0.25);
    border-radius: 14px;
    padding: 12px 16px;
    display: none;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    max-width: min(720px, calc(100vw - 24px));
    z-index: 10001;
    color: #f1f1f1;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.bulk-action-bar.visible {
    display: flex;
}
.bulk-action-bar-count {
    font-weight: 700;
    color: #2ecc71;
    flex: 0 0 auto;
}
.bulk-action-btn {
    background: #2ecc71;
    color: #0d3a1f;
    border: none;
    border-radius: 8px;
    padding: 10px 16px;
    min-height: 44px;
    cursor: pointer;
    font-weight: 600;
    font-size: 14px;
}
.bulk-action-btn:hover {
    background: #34d77f;
}
.bulk-action-btn-secondary {
    background: rgba(255, 255, 255, 0.1);
    color: #f1f1f1;
    border: 1px solid rgba(255, 255, 255, 0.2);
}
.bulk-action-btn-secondary:hover {
    background: rgba(255, 255, 255, 0.18);
}
.bulk-action-btn:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}
.bulk-action-select {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.18);
    color: #f1f1f1;
    padding: 8px 10px;
    border-radius: 8px;
    min-height: 44px;
    cursor: pointer;
    font-size: 13px;
    max-width: 180px;
}
.bulk-action-select:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}
.bulk-action-select option {
    color: #111;
    background: #fff;
}
@media (max-width: 480px) {
    .bulk-action-bar {
        max-width: calc(100vw - 24px);
        padding: 10px 12px;
    }
    .bulk-action-bar-count {
        flex-basis: 100%;
    }
    .bulk-action-select {
        max-width: 100%;
        flex: 1 1 100%;
    }
}
body.bulk-active .card-modal {
    padding-bottom: 80px;
}

/* Issue #448 — chip-styled inline modals replacing native prompt() / confirm()
   for the bulk-edit Set qty + threshold flows. Mirrors .collect-confirm-chip's
   gold-on-navy palette so the visual vocabulary stays consistent, but uses its
   own class so the singleton chip state isn't disturbed. */
.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.bulk-confirm-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(5, 8, 20, 0.45);
    z-index: 10010;
    opacity: 0;
    transition: opacity 180ms ease;
    pointer-events: auto;
}
.bulk-confirm-modal-backdrop.visible {
    opacity: 1;
}

.bulk-confirm-modal {
    position: fixed;
    left: 50%;
    bottom: calc(20px + env(safe-area-inset-bottom));
    transform: translateX(-50%) translateY(20px);
    opacity: 0;
    pointer-events: auto;
    background: rgba(20, 25, 50, 0.96);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border: 1px solid rgba(255, 215, 0, 0.25);
    border-radius: 14px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    z-index: 10011;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    max-width: min(480px, calc(100vw - 24px));
    color: #f1f1f1;
    transition: opacity 220ms cubic-bezier(0.2, 0.9, 0.3, 1),
                transform 220ms cubic-bezier(0.2, 0.9, 0.3, 1);
}
.bulk-confirm-modal.visible {
    transform: translateX(-50%) translateY(0);
    opacity: 1;
}
.bulk-confirm-modal-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: #fff;
}
.bulk-confirm-modal-body {
    font-size: 0.82rem;
    color: rgba(255, 255, 255, 0.72);
}
.bulk-confirm-modal-input-row {
    display: flex;
    align-items: center;
    gap: 8px;
    background: rgba(255, 255, 255, 0.06);
    border-radius: 10px;
    padding: 4px;
}
.bulk-confirm-modal-step {
    width: 44px;
    height: 44px;
    border-radius: 8px;
    border: none;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    font-size: 1.3rem;
    font-weight: 700;
    cursor: pointer;
}
.bulk-confirm-modal-step:hover {
    background: rgba(255, 255, 255, 0.18);
}
.bulk-confirm-modal-input {
    flex: 1 1 auto;
    min-width: 0;
    height: 44px;
    background: rgba(0, 0, 0, 0.25);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 8px;
    color: #fff;
    font-size: 1rem;
    font-weight: 600;
    text-align: center;
    padding: 0 8px;
}
.bulk-confirm-modal-input:focus-visible {
    outline: 2px solid #ffd700;
    outline-offset: 2px;
}
.bulk-confirm-modal-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}
.bulk-confirm-modal-btn {
    height: 44px;
    min-width: 88px;
    padding: 0 16px;
    border: none;
    border-radius: 10px;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    color: #fff;
}
.bulk-confirm-modal-cancel {
    background: rgba(255, 255, 255, 0.1);
}
.bulk-confirm-modal-cancel:hover {
    background: rgba(255, 255, 255, 0.18);
}
.bulk-confirm-modal-primary {
    background: #2ecc71;
    color: #0a1020;
}
.bulk-confirm-modal-primary:hover {
    background: #27ae60;
}
.bulk-confirm-modal-primary[data-style="danger"] {
    background: #e74c3c;
    color: #fff;
}
.bulk-confirm-modal-primary[data-style="danger"]:hover {
    background: #d6452a;
}
.bulk-confirm-modal-btn:focus-visible,
.bulk-confirm-modal-step:focus-visible {
    outline: 2px solid #ffd700;
    outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
    .bulk-confirm-modal,
    .bulk-confirm-modal-backdrop {
        transition: opacity 100ms ease;
    }
    .bulk-confirm-modal {
        transform: translateX(-50%);
    }
    .bulk-confirm-modal.visible {
        transform: translateX(-50%);
    }
}
@media (max-width: 480px) {
    .bulk-confirm-modal {
        max-width: calc(100vw - 16px);
    }
    .bulk-confirm-modal-actions {
        justify-content: stretch;
    }
    .bulk-confirm-modal-btn {
        flex: 1 1 auto;
        min-width: 0;
    }
}

.card-modal-graded-instances {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.card-modal-graded-title {
    font-size: 13px;
    font-weight: 600;
    color: #d4a017;
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.card-modal-graded-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.card-modal-graded-item {
    padding: 6px 10px;
    background: rgba(212, 160, 23, 0.12);
    border: 1px solid rgba(212, 160, 23, 0.35);
    border-radius: 4px;
    font-size: 13px;
    color: #fff;
}

/* Story 6.1 — custom-set insert form
   Scanner match → auto-populated confirmation modal. Matches the visual
   language of the other scan-stage modals (dark backdrop, centered card). */
.custom-insert-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1200;
    background: rgba(0, 0, 0, 0.78);
    align-items: center;
    justify-content: center;
    padding: 16px;
    overflow-y: auto;
}
.custom-insert-modal[data-open="true"],
.custom-insert-modal.open {
    display: flex;
}
.custom-insert-modal-content {
    position: relative;
    background: #14142b;
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 10px;
    max-width: 520px;
    width: 100%;
    padding: 24px 24px 20px;
    max-height: 92vh;
    overflow-y: auto;
    box-shadow: 0 12px 36px rgba(0, 0, 0, 0.55);
}
.custom-insert-modal-content h2 {
    font-size: 18px;
    margin: 0 0 8px;
    color: #ff9500;
}
.custom-insert-modal-close {
    position: absolute;
    top: 10px;
    right: 12px;
    background: transparent;
    border: none;
    color: #fff;
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
}
.custom-insert-modal-close:hover,
.custom-insert-modal-close:focus-visible {
    background: rgba(255, 255, 255, 0.08);
    outline: none;
}
.custom-insert-summary {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.78);
    margin: 4px 0 16px;
    line-height: 1.4;
}
.custom-insert-summary strong { color: #fff; }
.custom-insert-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.custom-insert-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.75);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.custom-insert-field input,
.custom-insert-field select {
    font-family: inherit;
    font-size: 14px;
    text-transform: none;
    letter-spacing: normal;
    color: #fff;
    background: rgba(0, 0, 0, 0.35);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 6px;
    padding: 8px 10px;
    box-sizing: border-box;
    width: 100%;
}
.custom-insert-field input:focus,
.custom-insert-field select:focus {
    outline: 2px solid #ff9500;
    outline-offset: 1px;
    border-color: transparent;
}
.custom-insert-error {
    color: #ff6b6b;
    font-size: 13px;
    min-height: 18px;
    margin: 4px 0 0;
}
.custom-insert-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 10px;
}

/* Story 6.2 — dedup UI. Shown in place of the insert form when the scanned
   card's apiId already exists in the selected custom set. */
.custom-insert-already {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px 16px;
    margin: 4px 0 4px;
    border: 1px solid rgba(255, 149, 0, 0.35);
    border-radius: 8px;
    background: rgba(255, 149, 0, 0.08);
}
.custom-insert-already[hidden] { display: none; }
.custom-insert-already-message {
    margin: 0;
    font-size: 14px;
    line-height: 1.45;
    color: #ffd89a;
}
.custom-insert-already-message strong { color: #fff; }
.custom-insert-already-detail {
    margin: 0;
    font-size: 13px;
    color: rgba(255, 255, 255, 0.82);
    display: flex;
    flex-wrap: wrap;
    gap: 6px 10px;
    align-items: baseline;
}
.custom-insert-already-apiid {
    font-family: 'Courier New', monospace;
    font-size: 12px;
    padding: 2px 6px;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.35);
    color: rgba(255, 255, 255, 0.75);
}
/* When the dedup UI is shown, the form + summary are hidden via the hidden
   attribute driven from js/custom-set-inserter.js. */
#customSetInsertFormSection[hidden],
#customSetInsertSummary[hidden] { display: none; }

/* ── Guest banner + read-only rendering (Story 8.3) ──────────────── */
/* The banner is always present in the DOM but only visible when the
   body carries the `guest-mode` class (toggled by setGuestMode in
   js/auth.js). Write-capable controls are hidden via body-scoped rules
   further down. Write-function gating is Story 8.4 / 8.5. */
.guest-banner {
    display: none;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 16px;
    background: linear-gradient(90deg, rgba(255, 215, 0, 0.14), rgba(0, 212, 255, 0.14));
    border-bottom: 1px solid rgba(255, 215, 0, 0.32);
    color: #fff;
    font-size: 0.92rem;
    position: sticky;
    top: 0;
    z-index: 9500;
    backdrop-filter: blur(6px);
}
body.guest-mode .guest-banner {
    display: flex;
}
.guest-banner-text {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 500;
    flex: 1;
    min-width: 0;
}
.guest-banner-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ffd700;
    box-shadow: 0 0 6px rgba(255, 215, 0, 0.7);
    flex-shrink: 0;
}
.guest-banner-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}
.guest-banner-btn {
    padding: 6px 14px;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid rgba(255, 255, 255, 0.3);
    background: transparent;
    color: #f1f1f1;
    font-family: inherit;
    transition: background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
    white-space: nowrap;
}
.guest-banner-btn:hover {
    background: rgba(255, 255, 255, 0.1);
}
.guest-banner-btn.primary {
    background: linear-gradient(135deg, #00ff88, #00d4ff);
    color: #000;
    border: none;
}
.guest-banner-btn.primary:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 255, 136, 0.45);
}
.guest-banner-btn:focus-visible {
    outline: 2px solid #ffd700;
    outline-offset: 2px;
}

/* Controls that mutate user state — hidden while browsing as guest.
   The underlying functions are additionally gated in Stories 8.4 / 8.5. */
body.guest-mode .sealed-qty-controls {
    display: none !important;
}

/* Story 8.6 — short "welcome back, pick up where you left off" toast shown
   after a guest signs in if their pending action needs an interactive UI
   that can't be auto-replayed (scanner flows, graded edits). */
.action-restored-toast {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%) translateY(20px);
    background: rgba(20, 30, 50, 0.96);
    color: #f1f1f1;
    border: 1px solid rgba(0, 255, 136, 0.5);
    border-radius: 10px;
    padding: 12px 18px;
    font-size: 0.92rem;
    max-width: 90vw;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    opacity: 0;
    transition: opacity 0.25s ease, transform 0.25s ease;
    z-index: 10002;
    pointer-events: none;
}
.action-restored-toast.visible {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

@media (max-width: 600px) {
    .guest-banner {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
        padding: 10px 12px;
    }
    .guest-banner-text { font-size: 0.85rem; }
    .guest-banner-actions { justify-content: stretch; }
    .guest-banner-btn { flex: 1; }
}

/* ── Landing overlay (Story 8.2) ─────────────────────────────────── */
/* Shown to unauthenticated first-time visitors in place of the immediate
   auth modal. Sits below the auth modal (z-index 10001) so CTAs that open
   the auth flow layer cleanly on top. */
.landing-overlay {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: linear-gradient(135deg, #1a1a4e 0%, #2d1b69 30%, #1a3a5c 70%, #162447 100%);
    overflow-y: auto;
    overflow-x: hidden;
    color: #f1f1f1;
    -webkit-font-smoothing: antialiased;
}
.landing-overlay[hidden] { display: none; }

.landing-bg {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
}
.landing-card {
    position: absolute;
    opacity: 0.35;
    filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.35));
}
.landing-card.lcard1 { top: 5%; left: -60px; width: 220px; height: 220px; transform: rotate(-15deg); }
.landing-card.lcard2 { bottom: 8%; right: -80px; width: 260px; height: 260px; transform: rotate(20deg); }
.landing-card.lcard3 { top: 35%; right: 12%; width: 110px; height: 110px; opacity: 0.28; }
.landing-pokeball-accent {
    position: absolute;
    opacity: 0.85;
    width: 32px;
    height: 32px;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.4));
}
.landing-pokeball-accent.lpb-a1 { top: 14%; left: 22%; animation: float-pokeball 5s ease-in-out infinite; }
.landing-pokeball-accent.lpb-a2 { top: 62%; right: 18%; width: 26px; height: 26px; animation: float-pokeball 6s ease-in-out infinite 1.5s; }

.landing-content {
    position: relative;
    z-index: 1;
    max-width: 960px;
    margin: 0 auto;
    padding: 48px 24px 64px;
    display: flex;
    flex-direction: column;
    gap: 40px;
}

.landing-hero {
    position: relative;
    text-align: center;
    padding: 24px 0 8px;
}
.landing-logo {
    width: min(460px, 88vw);
    height: auto;
    display: block;
    margin: 0 auto 18px;
    filter: drop-shadow(0 4px 16px rgba(255, 215, 0, 0.35));
}
.landing-headline {
    font-size: clamp(1.4rem, 3.6vw, 2rem);
    font-weight: 800;
    letter-spacing: 0.3px;
    margin: 0 auto 10px;
    background: linear-gradient(45deg, #ffd700, #ffed4e, #ffd700);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    max-width: 640px;
}
.landing-subcopy {
    font-size: 1rem;
    opacity: 0.82;
    max-width: 520px;
    margin: 0 auto;
    line-height: 1.5;
}
.landing-char {
    position: absolute;
    bottom: -8px;
    width: 64px;
    filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
    opacity: 0.9;
}
.landing-char-pikachu { right: 8%; width: 72px; }
.landing-char-psyduck { left: 8%; width: 64px; }
.landing-char-togepi  { left: 50%; transform: translateX(-50%); bottom: -16px; width: 50px; opacity: 0.75; }

.landing-marquee {
    position: relative;
    width: 100%;
    overflow: hidden;
    padding: 8px 0;
    -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0%, #000 8%, #000 92%, transparent 100%);
}
.landing-marquee-track {
    display: flex;
    gap: 56px;
    width: max-content;
    animation: landing-marquee-scroll 40s linear infinite;
}
.landing-marquee:hover .landing-marquee-track {
    animation-play-state: paused;
}
.landing-marquee-item {
    flex: 0 0 auto;
    width: 160px;
    height: 72px;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0.85;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.35));
}
.landing-marquee-item img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
@keyframes landing-marquee-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
    .landing-marquee-track { animation: none; }
    .header-pokemon-bg .pokeball-accent { animation: none; }
    .landing-pokeball-accent { animation: none; }
    .modal-qty-btn:active { transform: none; }
    body::before {
        animation: none;
        transform: translate3d(-1.5%, -1%, 0) scale(1.03);
        opacity: 1;
    }
    body::after {
        animation: none;
        opacity: 0.045;
    }
}

.landing-features {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 18px;
}
.landing-feature {
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 16px;
    padding: 22px 20px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}
.landing-feature-icon {
    width: 72px;
    height: 72px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.25);
    border: 1px solid rgba(255, 215, 0, 0.2);
}
.landing-feature-icon img {
    width: 56px;
    height: auto;
}
.landing-feature-icon-lorcana {
    background: linear-gradient(135deg, #4a148c, #6a1b9a);
    border-color: rgba(255, 255, 255, 0.2);
}
.landing-feature-icon-scanner {
    background: linear-gradient(135deg, #0e4f5f, #147a8b);
    border-color: rgba(0, 255, 200, 0.3);
    color: #8fe7d4;
}
.landing-feature-glyph {
    font-size: 2.2rem;
    color: #ffd700;
    line-height: 1;
}
.landing-feature-title {
    font-size: 1.05rem;
    font-weight: 700;
    color: #00ff88;
    margin: 0;
}
.landing-feature-text {
    font-size: 0.9rem;
    line-height: 1.5;
    opacity: 0.82;
    margin: 0;
}

.landing-cta {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding-top: 8px;
}
.landing-btn {
    min-width: 260px;
    padding: 14px 24px;
    border-radius: 10px;
    font-size: 1rem;
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
    font-family: inherit;
}
.landing-btn:focus-visible {
    outline: 2px solid #ffd700;
    outline-offset: 3px;
}
.landing-btn-primary {
    background: linear-gradient(135deg, #00ff88, #00d4ff);
    color: #000;
    border: none;
}
.landing-btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 255, 136, 0.45);
}
.landing-btn-secondary {
    background: transparent;
    color: #f1f1f1;
    border: 1px solid rgba(255, 255, 255, 0.35);
}
.landing-btn-secondary:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 215, 0, 0.6);
}
.landing-btn-link {
    background: transparent;
    border: none;
    color: #00d4ff;
    font-weight: 600;
    padding: 8px 16px;
    min-width: 0;
    text-decoration: underline;
    text-underline-offset: 3px;
}
.landing-btn-link:hover {
    color: #ffd700;
}
.landing-cta-footnote {
    font-size: 0.8rem;
    opacity: 0.65;
    max-width: 360px;
    text-align: center;
    margin: 0;
    line-height: 1.4;
}

@media (max-width: 1024px) {
    .landing-features { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 760px) {
    .landing-content { padding: 32px 16px 48px; gap: 28px; }
    .landing-features { grid-template-columns: 1fr; }
    .landing-marquee-item { width: 120px; height: 56px; }
    .landing-marquee-track { gap: 36px; animation-duration: 28s; }
    .landing-char { display: none; }
    .landing-pokeball-accent { display: none; }
    .landing-btn { min-width: 100%; }
    .landing-logo { margin-bottom: 14px; }
}

/* ── Custom Sets empty state (Epic 9) ────────────────────────── */
.custom-sets-empty {
    grid-column: 1 / -1;
    max-width: 640px;
    margin: 32px auto;
    padding: 40px 28px;
    background: linear-gradient(135deg, rgba(255, 149, 0, 0.06), rgba(255, 204, 0, 0.04));
    border: 1px dashed rgba(255, 149, 0, 0.35);
    border-radius: 16px;
    text-align: center;
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.06);
}
.custom-sets-empty-icon {
    width: 72px;
    height: 72px;
    margin: 0 auto 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.custom-sets-empty-icon img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    animation: float-pokeball 4s ease-in-out infinite;
}
.custom-sets-empty-title {
    margin: 0 0 12px;
    font-size: 22px;
    font-weight: 700;
    color: #f1f1f1;
}
.custom-sets-empty-desc {
    margin: 0 auto 22px;
    max-width: 520px;
    font-size: 15px;
    line-height: 1.55;
    color: rgba(241, 241, 241, 0.82);
}
.custom-sets-empty-cta {
    appearance: none;
    -webkit-appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 12px 24px;
    background: linear-gradient(135deg, #ff9500, #ffb347);
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    border: none;
    border-radius: 10px;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(255, 149, 0, 0.35);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.custom-sets-empty-cta:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(255, 149, 0, 0.45);
}
.custom-sets-empty-cta:active {
    transform: translateY(0);
    box-shadow: 0 2px 8px rgba(255, 149, 0, 0.35);
}
@media (max-width: 480px) {
    .custom-sets-empty {
        margin: 20px 12px;
        padding: 28px 18px;
    }
    .custom-sets-empty-title { font-size: 19px; }
    .custom-sets-empty-desc { font-size: 14px; }
    .custom-sets-empty-cta { width: 100%; }
}

/* ===== Modern background (multi-radial gradient + grain overlay) ===== */
/* Pseudo-elements at z-index: -1 sit behind `.container`, which establishes
   its own stacking context via `isolation: isolate`. Do not remove either
   piece without verifying modal/dropdown stacking still works. */
body::before {
  content: "";
  position: fixed;
  inset: -10%;
  z-index: -1;
  pointer-events: none;
  background-color: #14152a;
  background-image:
    radial-gradient(ellipse 60% 50% at 22% 28%, #2a2560 0%, transparent 55%),
    radial-gradient(ellipse 55% 45% at 78% 72%, #16355e 0%, transparent 60%),
    radial-gradient(ellipse 70% 60% at 50% 110%, #1d1f45 0%, transparent 65%);
  background-repeat: no-repeat;
  will-change: transform;
  animation:
    bgV2Enter 720ms cubic-bezier(0.22, 0.61, 0.36, 1) 1 both,
    bgV2Drift 90s ease-in-out 720ms infinite;
}

body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url("Images/bg/grain.svg");
  background-size: 200px 200px;
  opacity: 0;
  mix-blend-mode: overlay;
  animation: bgV2GrainEnter 1100ms ease-out 1 both;
}

@keyframes bgV2Drift {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-1.5%, -1%, 0) scale(1.03); }
}
@keyframes bgV2Enter {
  from { opacity: 0; transform: translate3d(0, 0, 0) scale(1.06); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}
@keyframes bgV2GrainEnter {
  from { opacity: 0; }
  to   { opacity: 0.045; }
}

@media print {
  body::before,
  body::after { display: none; }
}

@media (forced-colors: active) {
  body::before,
  body::after { display: none; }
}

/* Issue #394 — per-edition tracking on owned[] instances */
:root {
    --edition-pill-bg: rgba(100, 116, 139, 0.18);
    --edition-pill-fg: #cbd5e1; /* slate-300 — ~9:1 on the modal background */
}
.card-modal-editions-section {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.card-modal-editions-line {
    font-size: 0.85em;
    color: var(--edition-pill-fg);
    padding: 4px 8px;
    background: var(--edition-pill-bg);
    border-radius: 8px;
    margin: 8px 0;
    display: flex;
    gap: 8px;
    align-items: center;
}
.card-modal-editions-summary {
    flex: 1;
}
.card-modal-editions-edit {
    color: #2fb46a;
    cursor: pointer;
    text-decoration: underline;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
}
.card-modal-editions-edit-standalone {
    display: inline-block;
    font-size: 0.85em;
    margin: 8px 0;
}
.card-modal-editions-edit-list {
    display: none;
    margin-top: 6px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 6px;
    padding: 4px 0;
}
.modal-edition-row {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 6px 8px;
    border-bottom: 1px solid rgba(0,0,0,0.08);
}
.modal-edition-row:last-child { border-bottom: none; }
.modal-edition-select {
    flex: 1;
    padding: 6px 8px;
    border-radius: 6px;
    border: 1px solid rgba(255,255,255,0.18);
    background: rgba(255,255,255,0.04);
    color: inherit;
}
.modal-edition-remove {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: rgba(231, 76, 60, 0.12);
    color: #e74c3c;
    border: none;
    cursor: pointer;
    font-size: 18px;
    line-height: 1;
}
.modal-edition-remove:focus-visible,
.modal-edition-select:focus-visible,
.card-modal-editions-edit:focus-visible {
    outline: 2px solid #fbbf24;
    outline-offset: 2px;
}

/* ── Filter-flicker fix: CSS-first structural filter ───────────────────────
 * Container data-attributes drive per-card hiding via attribute selectors so
 * the filter applies the instant a card is inserted into the DOM. Chunked
 * renders and full-rebuild peer writes can no longer paint unfiltered cards
 * mid-frame because the CSS rule fires synchronously with insertion.
 *
 * Container attrs (set on .set-view-cards by applyFiltersAndSearch):
 *   data-filter-status      = "all" | "incomplete" | "complete"
 *   data-filter-rarities-active = "true" | absent
 *   data-filter-graded      = "any-graded" | "PSA" | "BGS" | "CGC" | "SGC" | absent
 *
 * Per-card attrs (set by buildPokemonGridCard / buildCustomGridCard /
 * buildLorcanaGridCard / ListView.buildRow at creation time, refreshed by
 * applyFiltersAndSearch):
 *   data-completed        = "true" | "false"
 *   data-rarity           = lowercased rarity
 *   data-rarity-match     = "true" when current rarity filter includes the card
 *   data-graded-state     = "any" when one or more graded instances exist
 *   data-graded-companies = space-separated company tokens (e.g. "PSA BGS")
 *   data-search-hidden    = "true" when current search query doesn't match
 *   data-leaving-filter   = "true" during the 180ms fade-on-leave window
 */

/* Smooth fade transitions so peer-update card-state changes don't snap.
 * Merged with `transition: all 0.2s` (styles.css:1494) so hover lift,
 * background, etc. still animate — only opacity uses the 180ms ramp. */
.card-item,
.card,
.card-list-row {
    transition: all 0.2s, opacity 180ms ease;
}

/* Status filter — hide completed in incomplete mode, hide incomplete in complete mode. */
.set-view-cards[data-filter-status="incomplete"] .card-item[data-completed="true"],
.set-view-cards[data-filter-status="incomplete"] .card[data-completed="true"],
.set-view-cards[data-filter-status="incomplete"] .card-list-row[data-completed="true"],
.set-view-cards[data-filter-status="complete"] .card-item[data-completed="false"],
.set-view-cards[data-filter-status="complete"] .card[data-completed="false"],
.set-view-cards[data-filter-status="complete"] .card-list-row[data-completed="false"] {
    display: none;
}

/* Rarity filter — when active, hide every card whose rarity isn't in the set. */
.set-view-cards[data-filter-rarities-active="true"] .card-item:not([data-rarity-match="true"]),
.set-view-cards[data-filter-rarities-active="true"] .card:not([data-rarity-match="true"]),
.set-view-cards[data-filter-rarities-active="true"] .card-list-row:not([data-rarity-match="true"]) {
    display: none;
}

/* Graded filter — any-graded hides cards with no graded instances. */
.set-view-cards[data-filter-graded="any-graded"] .card-item:not([data-graded-state="any"]),
.set-view-cards[data-filter-graded="any-graded"] .card:not([data-graded-state="any"]),
.set-view-cards[data-filter-graded="any-graded"] .card-list-row:not([data-graded-state="any"]) {
    display: none;
}

/* Graded filter — per-company hides cards lacking that company token. */
.set-view-cards[data-filter-graded="PSA"] .card-item:not([data-graded-companies~="PSA"]),
.set-view-cards[data-filter-graded="PSA"] .card:not([data-graded-companies~="PSA"]),
.set-view-cards[data-filter-graded="PSA"] .card-list-row:not([data-graded-companies~="PSA"]),
.set-view-cards[data-filter-graded="BGS"] .card-item:not([data-graded-companies~="BGS"]),
.set-view-cards[data-filter-graded="BGS"] .card:not([data-graded-companies~="BGS"]),
.set-view-cards[data-filter-graded="BGS"] .card-list-row:not([data-graded-companies~="BGS"]),
.set-view-cards[data-filter-graded="CGC"] .card-item:not([data-graded-companies~="CGC"]),
.set-view-cards[data-filter-graded="CGC"] .card:not([data-graded-companies~="CGC"]),
.set-view-cards[data-filter-graded="CGC"] .card-list-row:not([data-graded-companies~="CGC"]),
.set-view-cards[data-filter-graded="SGC"] .card-item:not([data-graded-companies~="SGC"]),
.set-view-cards[data-filter-graded="SGC"] .card:not([data-graded-companies~="SGC"]),
.set-view-cards[data-filter-graded="SGC"] .card-list-row:not([data-graded-companies~="SGC"]) {
    display: none;
}

/* Search — JS-driven per-card, since substring match isn't expressible as CSS. */
.card-item[data-search-hidden="true"],
.card[data-search-hidden="true"],
.card-list-row[data-search-hidden="true"] {
    display: none;
}

/* Two-phase fade-on-leave: data-leaving-filter holds the card visible at
 * opacity 0 during the 180ms transition before the actual structural attr
 * changes hide it via the rules above. */
.card-item[data-leaving-filter="true"],
.card[data-leaving-filter="true"],
.card-list-row[data-leaving-filter="true"] {
    opacity: 0;
}

/* Reduced-motion: skip the fade animation; the leaving state still applies
 * (opacity 0 immediately) so the structural hide on the timer cleanup is
 * visually identical to an instant disappear. */
@media (prefers-reduced-motion: reduce) {
    .card-item,
    .card,
    .card-list-row {
        transition: none;
    }
    .card-item.all-collected::after,
    .card.completed::after {
        animation: none;
    }
}
