/* Self-hosted display face — headings, stat numerals, wordmark. Latin subset only:
   Korean/Japanese glyphs fall through per-glyph to the system CJK fonts in the stack
   (see --font-display), which keeps mixed-script headings from going anemic. */
@font-face {
    font-family: 'Barlow Condensed';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('/fonts/barlow-condensed-500.woff2') format('woff2');
}

@font-face {
    font-family: 'Barlow Condensed';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('/fonts/barlow-condensed-600.woff2') format('woff2');
}

@font-face {
    font-family: 'Barlow Condensed';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('/fonts/barlow-condensed-700.woff2') format('woff2');
}

:root {
    --font-display: 'Barlow Condensed', 'Malgun Gothic', 'Yu Gothic UI', 'Apple SD Gothic Neo', 'Hiragino Sans', sans-serif;
    /* Body face, matching MudBlazor's default. Declared here because MudBlazor's own copy
       arrives with the circuit, and the shell paints before that. */
    --font-body: Roboto, Helvetica, Arial, sans-serif;
}

/* The shell paints before any circuit, and every --mud-* custom property is emitted by
   MudThemeProvider inside one — including the palette MudBlazor's own body rule reads. So the
   shell owns its base, from --mix-* tokens the server emits (docs/design/static-shell.md D5). */
body {
    background: var(--mix-bg);
    color: var(--mix-ink);
    font-family: var(--font-body);
}

/* MudBlazor 8.15 sizes a temporary drawer `width: var(--mud-drawer-width)` and puts no
   max-width on it anywhere, so a drawer declared wider than the glass hangs off the edge it
   is anchored to and nothing brings it back — a drawer scrolls vertically only. /Charts'
   filter drawer is 420px, which is past a folded Fold's cover screen. max-width beats width
   whatever the specificity, and a fixed element resolves the percentage against the viewport,
   so a declared width still applies wherever it fits and only an over-wide drawer is clamped.
   Site-wide because /Titles' detail drawer (400px) loses the same strip at 360px. */
.mud-drawer.mud-drawer-temporary {
    max-width: 100%;
}

/* Big-number treatment for stats (rating, Pumbility, scores). tabular-nums keeps digit
   columns steady while values tick up live. */
.stat-display {
    font-family: var(--font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: .02em;
}

/* ===== The circuit-drop overlay =====
   App.razor supplies #components-reconnect-modal, so Blazor stops building its own and just
   toggles state classes on ours. The framework's user-supplied-dialog path sets classes and
   nothing else — no inert, no scroll lock — so how much of the page an outage covers is
   decided entirely here, and it covers a corner. A dropped circuit leaves the rendered page
   readable: scrolling works, the static shell's nav works, and every navigation is a full
   document load, so a link the reader can still see and click is the fastest repair available
   to them. Dimming the page hid that and left them watching a spinner instead.
   Everything here is --mix-*: a dropped circuit is exactly the moment MudThemeProvider's
   --mud-* vars can't be relied on. Every rule is id-scoped because MudBlazor ships its own
   #components-reconnect-modal rules (background, z-index, and a
   `#components-reconnect-modal button` that outranks a bare class). */

#components-reconnect-modal {
    display: none;
    position: fixed;
    /* Docked, not draped: under the app bar, clear of the mobile bottom nav. */
    inset: auto;
    top: calc(var(--shell-appbar-h) + 8px);
    right: 8px;
    max-width: min(340px, calc(100vw - 16px));
    /* !important answers MudBlazor's own !important background; site.css loads after theirs. */
    background: none !important;
    /* The box shrink-wraps its card today, so this changes nothing today. It is what keeps a
       later padding or max-width edit from quietly parking a dead click zone over the page. */
    pointer-events: none;
}

/* No state class means no circuit trouble; -hide is the reconnected case. Both stay down.
   Every other class the framework can set has to be listed: an unlisted one leaves the box
   hidden, which is a frozen page with nothing on screen accounting for it. */
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-paused,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-resume-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
}

#components-reconnect-modal .reconnect-card {
    display: flex;
    gap: 12px;
    padding: 12px 15px;
    border-radius: 10px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    background: var(--mix-surface);
    color: var(--mix-ink);
    box-shadow: 0 14px 44px -16px color-mix(in srgb, var(--mix-bg) 90%, transparent);
    font-family: var(--font-body);
    text-align: left;
    /* The dock above is inert so the page keeps its clicks; the card takes its own back,
       because two of the three states carry a button that has to be reachable. */
    pointer-events: auto;
}

/* A dead session reads differently from a retry in progress: same box, louder edge. */
#components-reconnect-modal.components-reconnect-failed .reconnect-card,
#components-reconnect-modal.components-reconnect-resume-failed .reconnect-card,
#components-reconnect-modal.components-reconnect-rejected .reconnect-card {
    border-left: 3px solid var(--mix-secondary);
}

/* Paused is neither: the circuit is waiting to be picked up, not gone. */
#components-reconnect-modal.components-reconnect-paused .reconnect-card {
    border-left: 3px solid var(--mix-accent);
}

/* Every state ships; the class Blazor set decides which one has a box. */
#components-reconnect-modal .reconnect-state { display: none; }

#components-reconnect-modal.components-reconnect-show .reconnect-on-show,
#components-reconnect-modal.components-reconnect-paused .reconnect-on-paused,
#components-reconnect-modal.components-reconnect-failed .reconnect-on-failed,
#components-reconnect-modal.components-reconnect-resume-failed .reconnect-on-resume-failed,
#components-reconnect-modal.components-reconnect-rejected .reconnect-on-rejected {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

#components-reconnect-modal .reconnect-body {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

#components-reconnect-modal .reconnect-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    letter-spacing: .01em;
    line-height: 1.15;
}

/* Says which controls are dead. Undimmed, nothing else on screen says it. */
#components-reconnect-modal .reconnect-sub {
    margin: 0;
    font-size: .78rem;
    color: var(--mix-ink-muted);
}

/* -retrying rides on top of -show once the ladder starts backing off. Before that the
   attempts are instant, so there is no wait worth counting and the line stays down. */
#components-reconnect-modal .reconnect-retry-line {
    font-variant-numeric: tabular-nums;
}

#components-reconnect-modal:not(.components-reconnect-retrying) .reconnect-retry-line {
    display: none;
}

#components-reconnect-modal .reconnect-spinner {
    display: block;
    width: 20px;
    height: 20px;
    flex: none;
    margin-top: 3px;
    border-radius: 50%;
    border: 3px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    border-top-color: var(--mix-primary);
    animation: reconnect-spin .9s linear infinite;
}

@keyframes reconnect-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    #components-reconnect-modal .reconnect-spinner { animation-duration: 3s; }
}

#components-reconnect-modal .reconnect-btn {
    margin-top: 8px;
    align-self: flex-start;
    padding: 6px 14px;
    border-radius: 6px;
    border: 1px solid var(--mix-primary);
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
    /* The shorthand resets every font-* longhand, so the size must come after it. */
    font: inherit;
    font-size: .82rem;
    font-weight: 600;
    cursor: pointer;
}

#components-reconnect-modal .reconnect-btn:hover {
    background: color-mix(in srgb, var(--mix-primary) 85%, var(--mix-ink));
}

/* ===== Shell: app bar, wordmark, top nav, mega-menus, mix pill =====
   The bar and its menus are server-rendered HTML with no circuit behind them, so every value
   MudAppBar/MudMenu used to supply is pinned here. Heights and z-indexes match the MudTheme
   defaults they replace (docs/design/static-shell.md §9): appbar height is Dense
   (64px - 64px/4 = 48px) and ZIndex.AppBar is 1300, which is what keeps the bar stacked
   correctly against Mud's popovers (1200) and dialogs (1400). */

:root {
    --shell-appbar-h: 48px;
}

.shell-appbar {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    z-index: 1300;
    display: flex;
    align-items: center;
    gap: 4px;
    height: var(--shell-appbar-h);
    box-sizing: border-box;
    padding: 0 12px;
    background: var(--mix-nav);
    color: var(--mix-ink);
    box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12);
}

.shell-main {
    padding-top: var(--shell-appbar-h);
}

.shell-spacer {
    flex: 1 1 auto;
}

/* Breakpoint seam at Mud's Md (960px), replacing MudHidden — which needed JS to measure the
   viewport before it could decide what to render. Each side only ever hides: the elements
   themselves own their display value, because the bottom nav (flex) and the More sheet
   (block) don't share one. */
@media (max-width: 959.98px) {
    .shell-desktop-only {
        display: none !important;
    }
}

@media (min-width: 960px) {
    .shell-mobile-only {
        display: none !important;
    }
}

/* ===== Shell menus (the static stand-in for MudMenu + its popover) ===== */

.shell-menu {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.shell-menu-panel {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 1;
    display: none;
    min-width: 200px;
    max-width: calc(100vw - 16px);
    padding: 4px 0;
    border-radius: 4px;
    background: var(--mix-surface);
    box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
}

/* Menus at the bar's right edge open inward. nav.js shifts any panel that still overflows. */
.shell-menu-panel-end {
    left: auto;
    right: 0;
}

.shell-menu.open .shell-menu-panel {
    display: block;
}

.shell-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    cursor: pointer;
    font-size: .875rem;
    color: var(--mix-ink);
    text-decoration: none;
    white-space: nowrap;
    list-style: none;
}

.shell-menu-item:hover {
    background: rgba(255, 255, 255, .08);
    text-decoration: none;
}

.shell-menu-item::-webkit-details-marker {
    display: none;
}

.shell-menu-caption {
    padding: 4px 16px;
    font-size: .8rem;
    color: var(--mix-ink-muted);
}

.shell-menu-divider {
    margin: 4px 0;
    border-top: 1px solid rgba(255, 255, 255, .12);
}

/* Native disclosure carries the mix picker's collections and the More sheet's subgroups —
   no circuit, and keyboard support comes free. */
.shell-disclosure > summary {
    display: flex;
}

.shell-disclosure[open] > summary .mud-icon-root {
    transform: rotate(90deg);
}

.shell-disclosure-body .shell-menu-item {
    padding-left: 40px;
}

.shell-avatar-btn,
.shell-icon-btn {
    display: inline-flex;
    align-items: center;
    padding: 4px;
    background: none;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    color: var(--mix-ink);
}

.shell-avatar-btn:hover,
.shell-icon-btn:hover {
    background: rgba(255, 255, 255, .08);
}

.wordmark {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: .08em;
    color: var(--mix-ink);
    text-shadow: 0 0 12px var(--mix-glow);
    text-decoration: none;
    white-space: nowrap;
}

.top-nav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: 14px;
}

.top-nav-btn {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px 10px;
    border-radius: 6px;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: .95rem;
    letter-spacing: .05em;
    color: var(--mix-ink);
    text-decoration: none;
    white-space: nowrap;
}

.top-nav-btn:hover {
    background: rgba(255, 255, 255, .08);
}

/* Tier Lists is top-level when the bar has room for seven items and folds into Play when
   it doesn't. 1280 is MudBlazor's Lg — the ladder the rest of the app speaks — and it puts
   every tablet-landscape width (1024, 1180, 1194) on the folded side while every real
   laptop keeps the full bar. Both copies ship in the HTML; exactly one is ever shown. */
.nav-wide-only {
    display: none;
}

@media (min-width: 1280px) {
    .top-nav .nav-wide-only {
        display: inline-flex;
    }

    .nav-folded-only {
        display: none;
    }
}

.mix-pill {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: transparent;
    border: 1px solid var(--mix-primary);
    border-radius: 16px;
    padding: 3px 12px;
    cursor: pointer;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: .8rem;
    letter-spacing: .08em;
    color: var(--mix-ink);
    white-space: nowrap;
}

.mix-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--mix-primary);
    box-shadow: 0 0 8px var(--mix-glow);
}

/* App-bar chart search — a quiet pill that matches the mix pill, not a form field.
   The outlined border and dropdown caret are stripped; focus brings the theme primary in. */
.appbar-search .mud-input-control {
    margin: 0;
}

.appbar-search .mud-input.mud-input-outlined {
    background: rgba(255, 255, 255, .07);
    border-radius: 16px;
    font-size: .85rem;
}

.appbar-search .mud-input.mud-input-outlined:focus-within {
    background: rgba(255, 255, 255, .11);
    box-shadow: 0 0 0 1px var(--mix-primary);
}

.appbar-search .mud-input.mud-input-outlined input {
    color: var(--mix-ink);
    padding: 5px 14px;
    height: unset;
}

.appbar-search .mud-input.mud-input-outlined input::placeholder {
    color: var(--mix-ink-muted);
    opacity: 1;
}

.appbar-search .mud-input.mud-input-outlined .mud-input-outlined-border {
    border: none;
}

.appbar-search .mud-input-adornment {
    display: none;
}

/* One pulse when something opens the search programmatically (shell.openSearch) —
   settles into the same ring the focused field already wears. */
@media (prefers-reduced-motion: no-preference) {
    .appbar-search.search-flash .mud-input.mud-input-outlined {
        animation: search-flash .9s ease-out;
    }

    @keyframes search-flash {
        0% { box-shadow: 0 0 0 5px var(--mix-primary), 0 0 26px var(--mix-glow); }
        100% { box-shadow: 0 0 0 1px var(--mix-primary); }
    }
}

/* ===== Atmosphere: per-mix page-ground light, derived from each game's attract screen.
   Ground only — cards and surfaces stay flat so contrast is untouched. Trial feature:
   deleting a theme's block (or all three) fully removes it. ===== */

body.theme-phoenix {
    background:
        radial-gradient(1200px 800px at 85% -10%, rgba(255, 107, 53, .10), transparent 60%),
        radial-gradient(1000px 700px at 10% 110%, rgba(63, 169, 245, .08), transparent 60%),
        var(--mix-bg);
    background-attachment: fixed;
    min-height: 100vh;
}

body.theme-xx {
    background:
        radial-gradient(1100px 700px at 80% -10%, rgba(255, 47, 160, .10), transparent 60%),
        radial-gradient(900px 700px at 5% 105%, rgba(53, 200, 255, .08), transparent 60%),
        var(--mix-bg);
    background-attachment: fixed;
    min-height: 100vh;
}

body.theme-phoenix2 {
    background:
        radial-gradient(1200px 700px at 70% -15%, rgba(79, 227, 63, .10), transparent 55%),
        radial-gradient(1000px 800px at 15% 115%, rgba(43, 193, 216, .07), transparent 60%),
        var(--mix-bg);
    background-attachment: fixed;
    min-height: 100vh;
}

/* ===== Mobile: bottom nav + More sheet ===== */

.bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1300;
    display: flex;
    align-items: stretch;
    background: var(--mix-nav);
    border-top: 1px solid rgba(255, 255, 255, .08);
    padding-bottom: env(safe-area-inset-bottom);
}

.bottom-nav .bn {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 8px 0 9px;
    background: none;
    border: none;
    cursor: pointer;
    font-family: var(--font-display);
    font-size: .68rem;
    letter-spacing: .04em;
    color: var(--mix-ink-muted);
    text-decoration: none;
}

.bottom-nav .bn.active {
    color: var(--mix-primary);
}

/* The Communities slot only earns space on squarish viewports (fold phones, landscape). */
.bottom-nav .bn-wide {
    display: none;
}

@media (min-aspect-ratio: 1/1) {
    .bottom-nav .bn-wide {
        display: flex;
    }
}

/* Keep page content clear of the fixed bottom nav (Md breakpoint = 960px). */
@media (max-width: 959.98px) {
    .shell-main {
        padding-bottom: 72px;
    }

    /* Pages with a dock need clearance for both bars (the at-rest worst case). */
    html.has-dock .shell-main {
        padding-bottom: 132px;
    }
}

/* ===== Page dock (docs/design/randomizer-overhaul.md) =====
   Page-registered primary actions above the bottom nav. Scrolling down slides the
   nav away (html.nav-away, set by page-dock.js) and the dock takes the bottom edge;
   both bars only coexist at rest. */

:root {
    --bottom-nav-h: calc(53px + env(safe-area-inset-bottom));
}

.bottom-nav {
    transition: transform .25s ease;
}

html.nav-away .bottom-nav {
    transform: translateY(110%);
}

.page-dock {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--bottom-nav-h);
    z-index: 1299;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    background: var(--mix-nav);
    border-top: 1px solid rgba(255, 255, 255, .08);
    transition: bottom .25s ease, padding-bottom .25s ease;
}

html.nav-away .page-dock,
html.focus-mode .page-dock {
    bottom: 0;
    padding-bottom: calc(8px + env(safe-area-inset-bottom));
}

@media (prefers-reduced-motion: reduce) {
    .bottom-nav,
    .page-dock {
        transition: none;
    }
}

/* Focus mode: shell chrome gone. The page owes the user an explicit exit affordance.
   Both bars are server-rendered now, so both are hidden here rather than skipped. */
html.focus-mode .shell-appbar,
html.focus-mode .bottom-nav {
    display: none !important;
}

html.focus-mode .shell-main {
    padding-top: 12px;
}

/* The mobile More sheet, replacing MudDrawer's temporary-bottom variant. It hides by
   translating its own height off-screen, so the height must be fixed — "auto" leaves nothing
   to translate and the sheet renders permanently open. */
.more-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1400;
    height: 75vh;
    overflow-y: auto;
    background: var(--mix-nav);
    transform: translateY(100%);
    transition: transform .225s cubic-bezier(0, 0, .2, 1);
    scrollbar-width: none;
}

.more-sheet::-webkit-scrollbar {
    display: none;
}

.more-sheet.open {
    transform: translateY(0);
}

.more-sheet-body {
    padding: 8px 0 16px;
}

.more-sheet-scrim {
    position: fixed;
    inset: 0;
    z-index: 1399;
    background: rgba(0, 0, 0, .5);
    opacity: 0;
    pointer-events: none;
    transition: opacity .225s cubic-bezier(0, 0, .2, 1);
}

html.sheet-open .more-sheet-scrim {
    opacity: 1;
    pointer-events: auto;
}

/* The search sheet drops from the TOP, unlike More. The phone keyboard takes the bottom half
   of the screen the moment the input focuses, so a bottom-anchored field opens underneath the
   thing typing into it. It is only as tall as it needs to be — this asks one question. */
.search-sheet {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    z-index: 1400;
    background: var(--mix-nav);
    border-bottom: 1px solid rgba(255, 255, 255, .10);
    transform: translateY(-100%);
    transition: transform .225s cubic-bezier(0, 0, .2, 1);
}

.search-sheet.open {
    transform: translateY(0);
}

.search-sheet-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 16px 18px;
}

.search-sheet-label {
    font-family: var(--font-display);
    font-size: .6875rem;
    letter-spacing: .08em;
    line-height: 1.4;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

/* The autocomplete's popover is teleported to the provider at the document root, so it is
   never clipped by this box — the sheet only has to frame the input. */
.search-sheet-input {
    display: flex;
    align-items: center;
}

/* A thumb target, not an app-bar accent: taller than the desktop pill, and never under 16px
   — iOS Safari zooms the whole viewport when a smaller input takes focus. */
.search-sheet-input .mud-input.mud-input-outlined {
    width: 100%;
    border-radius: 10px;
}

.search-sheet-input .mud-input.mud-input-outlined input {
    padding: 11px 14px;
    font-size: 1rem;
}

/* The group head is a section label by default. nav.js promotes it to a tappable row when
   the viewport is too narrow for the grid; until then its chevron stays hidden so it never
   advertises an interaction it doesn't have. */
.more-sheet .more-group-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 16px 2px;
    font-family: var(--font-display);
    font-size: .6875rem;
    letter-spacing: .08em;
    line-height: 1.4;
    text-transform: uppercase;
    opacity: .65;
}

.more-sheet .more-group-head .mud-icon-root {
    font-size: .95rem;
}

.more-sheet .more-group-chevron,
.more-sheet .more-back {
    display: none;
}

/* ---- Drill-down: narrow, tall viewports ----------------------------------------------
   No horizontal room for tiles, so the groups collapse to a root list of section names and
   open one at a time. nav.js adds .drill-mode (layout is narrow) and .drill-inside (a group
   is open); the markup is identical to the grid's. */
.more-sheet .drill-mode .more-group-head {
    padding: 8px 16px;
    font-family: var(--font-body);
    font-size: .875rem;
    letter-spacing: normal;
    text-transform: none;
    opacity: 1;
    cursor: pointer;
}

.more-sheet .drill-mode .more-group-head:hover,
.more-sheet .drill-mode .more-group-head:focus-visible {
    background: rgba(255, 255, 255, .08);
}

.more-sheet .drill-mode .more-group-head .mud-icon-root {
    font-size: 1.25rem;
}

/* Pushed to the far edge so the row reads as "there is more this way". */
.more-sheet .drill-mode .more-group-chevron {
    display: inline-flex;
    margin-left: auto;
    opacity: .5;
}

.more-sheet .drill-mode .more-group-body {
    display: none;
}

.more-sheet .drill-mode .more-group.drill-open .more-group-body {
    display: block;
}

/* The open group's own head is redundant once the back bar names the section. */
.more-sheet .drill-mode .more-group.drill-open .more-group-head {
    display: none;
}

.more-sheet .drill-mode.drill-inside > .shell-menu-item {
    display: none;
}

.more-sheet .drill-mode .more-back {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 10px 16px;
    background: none;
    border: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
    color: var(--mix-primary);
    font-family: var(--font-display);
    font-size: .9375rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    cursor: pointer;
}

/* ---- Icon grid: squarish or wide viewports -------------------------------------------
   The aspect half is the same rule the bottom nav's wide-only slot uses (fold phones,
   landscape). The width floor catches portrait tablets, which are taller than 1:1 but have
   room to spare. Above 960 none of this applies — the desktop top nav has taken over. */
@media (min-aspect-ratio: 1/1), (min-width: 700px) {
    .more-sheet .more-group-body {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
        gap: 6px;
        padding: 4px 10px 2px;
    }

    .more-sheet .more-group-body .shell-menu-item {
        flex-direction: column;
        gap: 6px;
        min-height: 82px;
        padding: 12px 6px 10px;
        border-radius: 10px;
        background: var(--mix-surface);
        text-align: center;
        white-space: normal;
    }

    .more-sheet .more-group-body .shell-menu-item .mud-icon-root {
        font-size: 1.4rem;
    }

    /* Two lines, then ellipsis. Tournament names are owner-authored and can be any length,
       so the tile has to survive one without stretching the row it sits in. */
    .more-sheet .more-group-body .shell-menu-item span {
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
        font-size: .75rem;
        line-height: 1.25;
    }
}

@media (prefers-reduced-motion: reduce) {
    .more-sheet,
    .more-sheet-scrim {
        transition: none;
    }
}

/* ===== Randomizer draw cards (docs/design/randomizer-overhaul.md) =====
   Rides the tier-chart-card base. Held deliberately wears the mix-primary ring, NOT
   the owner-locked pass-green; vetoed dims + strikes in place (state words print in
   chips/tooltips, so hue never travels alone). */

.draw-card-order {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    border-radius: 6px;
    display: grid;
    place-items: center;
    background: var(--mix-accent);
    color: var(--mix-primary-contrast);
    font-size: .72rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .55);
}

/* Held/vetoed border rules live with the tier-card border language further down —
   the base card declares a `border` shorthand at equal specificity, so source order
   is what lets the state colors win (same rule as the pass/To-Do states). */

.draw-card-vetoed .tier-chart-card-jacket {
    filter: grayscale(.85) brightness(.5);
}

.draw-card-vetoed .draw-card-name {
    text-decoration: line-through;
    color: var(--mud-palette-text-secondary);
}

.draw-card-state-chip {
    position: absolute;
    bottom: 4px;
    right: 4px;
    border-radius: 6px;
    padding: 1px 7px;
    font-size: .62rem;
    font-weight: 800;
    letter-spacing: .07em;
    text-transform: uppercase;
}

.draw-card-state-held-chip {
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
}

.draw-card-state-vetoed-chip {
    background: var(--mud-palette-error);
    color: var(--mud-palette-error-text);
}

/* Compact keeps a name line (identity survives unfamiliar jackets, rule 2). */
.draw-card .tier-chart-card-name {
    font-size: .72rem;
    line-height: 1.5;
    display: block;
}

/* ===== Randomizer page (draw-first layout) ===== */

.rand-header {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}


.rand-anon-note {
    color: var(--mix-ink-muted);
    margin-bottom: 4px;
}

.rand-chipbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 2px;
    margin: 4px 0;
}

.rand-countline {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-bottom: 8px;
}

.rand-count-n {
    font-weight: 800;
    color: var(--mix-primary);
    font-variant-numeric: tabular-nums;
}

.rand-count-label {
    font-size: .78rem;
    color: var(--mix-ink-muted);
}

.rand-actionbar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

/* Reference strip below the cards: what this draw was configured with. */
.rand-draw-settings {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 2px;
    margin-top: 18px;
    opacity: .8;
}

.rand-draw-settings-label {
    font-family: var(--font-display);
    font-size: .68rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin-right: 8px;
}

.rand-grid {
    display: grid;
    gap: 8px;
}

.rand-grid-compact {
    grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
}

.rand-grid-comfortable {
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
}

/* A ghost of the card that will land there: same shape, surface, and radius as a
   tier-chart-card, dashed to read as "empty slot". */
.rand-add-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    border: 2px dashed var(--mud-palette-lines-default);
    border-radius: 8px;
    background: var(--mud-palette-surface);
    color: var(--mix-ink-muted);
    min-height: 104px;
    cursor: pointer;
}

.rand-add-tile:hover {
    border-color: var(--mix-primary);
    color: var(--mix-ink);
}

.rand-add-tile-plus {
    font-size: 1.6rem;
    line-height: 1;
}

.rand-add-tile-label {
    font-family: var(--font-display);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .05em;
}

.rand-add-tile:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

.rand-add-anchor {
    display: flex;
}

.rand-add-anchor .rand-add-tile {
    flex: 1;
    width: 100%;
}

.rand-add-pop {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 300px;
    max-width: 90vw;
}

/* New match popover (round 12): the panel content inside whichever trigger's popover. */
.rand-new-match-pop {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 300px;
    max-width: 90vw;
    padding: 14px;
}

/* Header + empty-state anchors hug their button; the dock anchor fills the CTA slot. */
.rand-newmatch-anchor {
    display: inline-flex;
}

.dock-cta-anchor {
    flex: 1;
    display: flex;
}

.rand-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 40px 16px;
    text-align: center;
    color: var(--mix-ink-muted);
}

.rand-table .rand-table-order {
    font-weight: 800;
    color: var(--mix-accent);
    font-variant-numeric: tabular-nums;
    width: 34px;
}

.rand-table .rand-table-name {
    font-weight: 600;
}

.rand-table .rand-table-actions {
    text-align: right;
    white-space: nowrap;
}

.rand-row-vetoed .rand-table-name {
    text-decoration: line-through;
    color: var(--mud-palette-text-secondary);
}

.rand-row-held .rand-table-name {
    color: var(--mix-primary);
}

.rand-drawer {
    display: flex;
    flex-direction: column;
}

.rand-drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px 16px 8px;
}

/* The drawer is viewport-wide (bottom sheet), but its content column isn't — full-bleed
   controls floated the Advanced toggle mid-screen on desktop (round 7). */
.rand-drawer-body > * {
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
}

.rand-drawer-footer > * {
    flex-shrink: 0;
}

.rand-drawer-footer {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
    border-top: 1px solid rgba(255, 255, 255, .08);
}

.rand-footer-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    width: 100%;
    max-width: 720px;
    margin: 0 auto;
}

.rand-drawer-count {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-right: auto;
}

.rand-save-name {
    max-width: 200px;
}

/* Dock content shared by randomizer (and future dock pages). */
.page-dock .dock-cta {
    flex: 1;
    height: 44px;
    border-radius: 12px;
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
    font-weight: 800;
    letter-spacing: .04em;
    box-shadow: 0 0 20px var(--mix-glow);
}

.page-dock .dock-side {
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 12px;
}

/* Tournament context + draft mode (docs/design/randomizer-overhaul.md C9). */

.rand-context-select {
    max-width: 260px;
}

.rand-create-tournament {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: 10px;
    padding: 10px 12px;
    margin: 6px 0;
}

.rand-create-tournament .mud-input-control {
    flex: 1;
    min-width: 200px;
}

.rand-invites {
    display: flex;
    flex-direction: column;
    gap: 6px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 10px;
    padding: 10px 12px;
    margin: 6px 0;
}

.rand-invite-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.rand-invite-role {
    font-weight: 700;
    font-size: .82rem;
    min-width: 82px;
}

.rand-invite-expiry {
    font-size: .78rem;
    color: var(--mix-ink-muted);
    margin-right: auto;
}

.rand-invite-mint {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    border-top: 1px dashed var(--mud-palette-lines-default);
    padding-top: 8px;
}

.rand-invite-mint .mud-input-control {
    max-width: 150px;
}

/* Match picker (round 9): rides the header, right-aligned — the field carries only
   "which match am I looking at". New match joins it on desktop; the dock CTA covers
   phones. On phone widths it takes its own full line instead of squeezing the title. */
.rand-header-match {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 10px;
}

.rand-header-match .rand-match-select {
    min-width: 200px;
    max-width: 300px;
}

@media (max-width: 599.98px) {
    .rand-header-match {
        flex: 1 1 100%;
        margin-left: 0;
    }

    .rand-header-match .rand-match-select {
        max-width: none;
        flex: 1;
    }
}

/* Manage-tournament drawer (round 8): stacked role-layered sections. */
.rand-manage-section {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 26px;
}

.rand-manage-heading {
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--mix-ink-muted);
}

.rand-manage-rename {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.rand-manage-rename .mud-input-control {
    flex: 1;
    min-width: 200px;
}

.rand-manage-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.rand-staff-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.rand-staff-row .rand-invite-role {
    margin-right: auto;
}

/* Draft mode: the staff tablet in player hands — loud mode control, explicit exit. */
.rand-draft-head {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

/* Two-line preset items: name + summary — legible on touch, no hover needed. */
.rand-preset-item {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    padding: 2px 0;
}

.rand-preset-name {
    font-weight: 700;
    font-size: .85rem;
}

/* Summaries render only on the open dropdown's list items — the closed select shows
   just the preset name (round 7: the two-line clone skewed the input's layout).
   Scoped to .mud-list-item, not .mud-popover, so it stays hidden even when the whole
   select lives inside another popover, like the New match panel (round 12). */
.rand-preset-summary {
    display: none;
    font-size: .7rem;
    color: var(--mix-ink-muted);
}

.mud-list-item .rand-preset-summary {
    display: block;
}

.rand-preset-select {
    min-width: 220px;
}

.rand-drawer-presets {
    margin-bottom: 14px;
}

.rand-exit-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 999px;
    padding: 6px 14px;
    background: none;
    cursor: pointer;
    font-size: .82rem;
    font-weight: 700;
    color: var(--mix-ink);
}

.rand-tour-pill {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 999px;
    padding: 6px 14px;
    font-size: .82rem;
    font-weight: 700;
    background: var(--mix-surface);
}

.rand-draft-armed {
    margin-bottom: 12px;
}

.rand-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-display);
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .14em;
    color: var(--mud-palette-error);
}

.rand-live-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--mud-palette-error);
    box-shadow: 0 0 8px var(--mud-palette-error);
    animation: rand-live-pulse 1.6s infinite;
}

@keyframes rand-live-pulse {
    50% {
        opacity: .35;
    }
}

@media (prefers-reduced-motion: reduce) {
    .rand-live-dot {
        animation: none;
    }
}

.rand-legend {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .72rem;
    color: var(--mix-ink-muted);
    margin-left: 10px;
}

.rand-legend i {
    width: 10px;
    height: 10px;
    border-radius: 3px;
}

.rand-legend-held {
    background: var(--mix-primary);
}

.rand-legend-vetoed {
    background: var(--mud-palette-error);
}

.page-dock .rand-staff-btn {
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 12px;
    color: var(--mud-palette-error);
}

/* ===== Randomizer settings panel ===== */

.rand-settings {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.rand-settings-row {
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.rand-settings-label {
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .04em;
}

.rand-type-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.rand-count-presets {
    display: flex;
    align-items: center;
    gap: 6px;
}

.rand-count-preset,
.rand-coop-chip,
.rand-seg,
.rand-grade-chip {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 9px;
    background: none;
    cursor: pointer;
    color: var(--mix-ink-muted);
    font-family: var(--font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.rand-count-preset {
    min-width: 40px;
    padding: 7px 0;
    font-size: .82rem;
}

.rand-count-custom {
    max-width: 76px;
}

.rand-count-preset.on,
.rand-coop-chip.on,
.rand-seg.on,
.rand-grade-chip.on {
    background: var(--mix-primary);
    border-color: var(--mix-primary);
    color: var(--mix-primary-contrast);
}

.rand-coop-chips {
    display: flex;
    gap: 6px;
}

.rand-coop-chip {
    padding: 6px 13px;
    font-size: .8rem;
}

.rand-seg-group {
    display: flex;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 9px;
    overflow: hidden;
}

.rand-seg {
    flex: 1;
    border: none;
    border-radius: 0;
    padding: 8px 0;
    font-size: .78rem;
}

.rand-grade-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}

.rand-grade-chip {
    padding: 4px 10px;
    font-size: .72rem;
}

.rand-gated-reason {
    color: var(--mix-ink-muted);
}

.rand-advanced-toggle {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    text-align: left;
    gap: 8px;
    width: 100%;
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: 10px;
    padding: 10px 12px;
    background: none;
    cursor: pointer;
    color: var(--mix-ink-muted);
    font-size: .8rem;
}

/* Slider heads carry a lone switch/note that belongs on the right; the Co-Op head
   still has its label on the left (round 10 fix — a blanket flex-end dragged it over). */
.rand-type-head > :only-child {
    margin-left: auto;
}

.rand-advanced-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: 8px;
}

/* Opt-in advanced sections: a quiet switch row until enabled. */
.rand-adv-section {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 10px;
    padding: 4px 12px 6px;
}

.rand-adv-section-head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.rand-adv-section-content {
    padding: 6px 2px 8px;
}

.rand-section-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.rand-owned-note {
    color: var(--mix-ink-muted);
}

.rand-section-hint {
    color: var(--mix-ink-muted);
    display: block;
}

.rand-weighted-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding-top: 4px;
}

.rand-min-mode {
    max-width: 440px;
}

.folder-grid {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 6px;
}

.rand-plain-rows {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 4px;
}

.rand-coop-bounds {
    display: flex;
    gap: 10px;
}

/* Dynamic weight rows (FolderWeightList). */
.weight-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    align-items: flex-start;
}

.weight-row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.weight-row-label {
    min-width: 52px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: .82rem;
    font-variant-numeric: tabular-nums;
}

.weight-row-weight {
    font-size: .7rem;
    color: var(--mix-ink-muted);
}

.weight-row-field {
    max-width: 90px;
}

/* ===== Armed action selector ===== */

.armed-selector {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.armed-selector-label {
    font-family: var(--font-display);
    font-size: .68rem;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.armed-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 2px solid var(--mud-palette-lines-default);
    border-radius: 11px;
    padding: 8px 16px;
    background: none;
    cursor: pointer;
    font-family: var(--font-display);
    font-size: .8rem;
    font-weight: 800;
    letter-spacing: .04em;
    color: var(--mix-ink-muted);
}

.armed-btn:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

.armed-btn-on {
    background: var(--mix-primary);
    border-color: var(--mix-primary);
    color: var(--mix-primary-contrast);
    box-shadow: 0 0 18px var(--mix-glow);
}

.armed-btn-on-veto {
    background: var(--mud-palette-error);
    border-color: var(--mud-palette-error);
    color: var(--mud-palette-error-text);
}

/* Staff-tablet sizing: readable at arm's length, tappable in a hurry. */
.armed-selector-loud .armed-btn {
    padding: 12px 24px;
    font-size: .95rem;
    border-radius: 13px;
}

/* ===== Level range slider (dual thumb) ===== */

.range-slider {
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* A thumb's centre travels between half a thumb in from each end, never the full box.
       The fill and the tick rail both measure against that inset so all three agree; the
       fill's calc lives in RangeSlider.razor because the script painting a drag writes the
       same expression. One size across engines: Firefox's default thumb is smaller, and a
       band that reads 20px on one browser and 14px on another is 14px to plan for. */
    --range-thumb: 20px;
}

.range-slider-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.range-slider-label {
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .04em;
}

.range-slider-value {
    margin-left: auto;
    font-family: var(--font-display);
    font-size: .78rem;
    color: var(--mix-primary);
    font-variant-numeric: tabular-nums;
}

.range-slider-track-wrap {
    position: relative;
    height: 28px;
}

.range-slider-track {
    position: absolute;
    top: 12px;
    left: 0;
    right: 0;
    height: 4px;
    border-radius: 2px;
    background: var(--mix-surface-muted);
}

.range-slider-fill {
    position: absolute;
    top: 12px;
    height: 4px;
    border-radius: 2px;
    background: var(--mix-primary);
    box-shadow: 0 0 8px var(--mix-glow);
}

/* Two overlaid native inputs; only the thumbs take pointer events. */
.range-slider-track-wrap input[type=range] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 28px;
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
    pointer-events: none;
}

.range-slider-track-wrap input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    pointer-events: auto;
    width: var(--range-thumb);
    height: var(--range-thumb);
    border-radius: 50%;
    background: var(--mix-primary);
    border: 3px solid var(--mix-bg);
    box-shadow: 0 0 0 1.5px var(--mix-primary);
    cursor: pointer;
    margin-top: 4px;
}

.range-slider-track-wrap input[type=range]::-moz-range-thumb {
    pointer-events: auto;
    box-sizing: border-box;
    width: var(--range-thumb);
    height: var(--range-thumb);
    border-radius: 50%;
    background: var(--mix-primary);
    border: 3px solid var(--mix-bg);
    box-shadow: 0 0 0 1.5px var(--mix-primary);
    cursor: pointer;
}

.range-slider-ticks {
    position: relative;
    height: 14px;
    margin: 0 calc(var(--range-thumb) / 2);
}

.range-slider-ticks span {
    position: absolute;
    transform: translateX(-50%);
    font-family: var(--font-display);
    font-size: .6rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.range-slider-disabled .range-slider-fill {
    background: var(--mix-surface-muted);
    box-shadow: none;
}

.range-slider-disabled .range-slider-value {
    color: var(--mix-ink-muted);
}

.range-slider-disabled input[type=range]::-webkit-slider-thumb {
    background: var(--mix-ink-muted);
    box-shadow: 0 0 0 1.5px var(--mix-ink-muted);
    opacity: .5;
    cursor: default;
}

.range-slider-disabled input[type=range]::-moz-range-thumb {
    background: var(--mix-ink-muted);
    box-shadow: 0 0 0 1.5px var(--mix-ink-muted);
    opacity: .5;
    cursor: default;
}

/* Rarity treatment ramp — glow intensity rises with the band. Hue alone can't order the
   bands monotonically (gold is brighter than sapphire), so treatment does; the percentile
   number always rides alongside, so color is never the only channel. Shadows omit a color
   on purpose: they take currentColor from the band hue. */
.rarity-glow-1 {
    text-shadow: 0 0 6px;
}

.rarity-glow-2 {
    text-shadow: 0 0 4px, 0 0 10px;
}

.rarity-glow-3 {
    text-shadow: 0 0 4px, 0 0 10px, 0 0 18px;
    font-weight: 600;
}

/* Legacy difficulty chips (docs/design/legacy-mixes.md): rendered, not image bubbles.
   Pre-Exceed slots, Half-Doubles, and levelled legacy co-ops announce "different
   scale" by looking deliberately unlike the modern bubble art. Hue rides the
   --slot-* tokens via inline style from ThemeScales.SlotColor. */
.legacy-chip {
    display: inline-flex;
    align-items: center;
    border: 2px solid var(--slot-neutral);
    border-radius: 12px;
    padding: 1px 8px;
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: .06em;
    color: var(--slot-neutral);
    white-space: nowrap;
    line-height: 1.5;
}
/* ===== Tier-list component vocabulary: sections, chart cards + the border language,
   lamp strip, border legend, folder picker. These back Components/* (TierSection,
   TierListChartCard, TierListSkeleton, LampStrip, BorderLegend, FolderPicker), so they
   live here rather than in any page's style block — the components must render
   correctly wherever they're reused. ===== */

.tier-section {
    margin: 12px 0;
}

.tier-section-header {
    display: flex;
    align-items: baseline;
    gap: 8px;
    cursor: pointer;
    border-left: 4px solid var(--tier-section-color, var(--mud-palette-text-secondary));
    padding-left: 8px;
}

.tier-section-name {
    color: var(--tier-section-color, var(--mud-palette-text-secondary));
}

.tier-section-count, .tier-section-stat {
    color: var(--mud-palette-text-secondary);
}

.tier-section-body {
    margin-top: 8px;
}

.tier-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 10px;
}

.tier-card-grid-compact {
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 6px;
}

.tier-chart-card {
    border: 2px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    background: var(--mud-palette-surface);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.tier-chart-card-jacket {
    height: 92px;
    background-size: cover;
    background-position: center;
    position: relative;
}

.tier-chart-card-bubble {
    position: absolute;
    top: 4px;
    left: 4px;
}

.tier-chart-card-body {
    padding: 4px 8px;
    min-width: 0;
    flex-grow: 1;
}

.tier-chart-card-name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tier-chart-card-actions {
    display: flex;
    align-items: center;
    padding: 0 4px 4px;
}

.tier-chart-card-compact {
    cursor: pointer;
}

.tier-chart-card-compact-jacket {
    height: 72px;
}

.tier-chart-card-compact-grade {
    position: absolute;
    bottom: 3px;
    right: 3px;
    background: var(--mud-palette-background);
    border-radius: 4px;
    padding: 1px 3px;
}

/* A printed value in the jacket corner. Opaque backdrop rather than a tint, because it
   sits on album art and has to stay legible over any of it. */
.tier-chart-card-corner {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12px;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
    background: rgba(0, 0, 0, .82);
    color: var(--mix-ink);
    padding: 1px 5px;
    border: 1px solid transparent;
}

/* The jacket's other bottom corner. Position only — the chrome rides .tier-chart-card-corner
   alongside it, so the two badges cannot drift apart. Declared after it so the tighter
   padding a picture wants beats the padding a printed value wants, on source order. */
.tier-chart-card-corner-start {
    position: absolute;
    bottom: 3px;
    left: 3px;
    display: flex;
    align-items: center;
    border-radius: 4px;
    padding: 1px 3px;
}

/* Play affordance on the jacket — .chart-card-play's treatment at card scale. Revealed on
   hover, always present for keyboard. */
.tier-chart-card-play {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    z-index: 2;
}

.tier-chart-card-play-glyph {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding-left: 3px;
    border-radius: 99px;
    background: rgba(0, 0, 0, .8);
    border: 1px solid rgba(255, 255, 255, .2);
    color: #fff;
    opacity: 0;
    transform: scale(.8);
    transition: opacity .12s ease, transform .12s ease;
}

.tier-chart-card-play-glyph::before {
    content: "";
    border-style: solid;
    border-width: 6px 0 6px 10px;
    border-color: transparent transparent transparent currentColor;
}

.tier-chart-card-play:hover .tier-chart-card-play-glyph,
.tier-chart-card-play:focus-visible .tier-chart-card-play-glyph {
    opacity: 1;
    transform: scale(1);
    border-color: var(--mix-primary);
}

@media (prefers-reduced-motion: reduce) {
    .tier-chart-card-play-glyph {
        transition: none;
    }
}

.tier-chart-card-extra {
    margin-top: 2px;
}

.tier-chart-card-lens-dot {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .45);
}

.tier-chart-card-tier {
    display: block;
}

.tier-chart-card-meta {
    display: block;
    color: var(--mud-palette-text-secondary);
}

.tier-chart-card-skills {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
    padding-bottom: 4px;
}

.tier-chart-card-skill {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    padding: 0 5px;
    font-size: .65rem;
    color: var(--mud-palette-text-secondary);
    white-space: nowrap;
}

/* Category-tinted chips (piucenter variant B): identity hue per skill category via
   the --skillcat-* tokens; the printed name carries the meaning (rule 8). */
.skillcat-speed { --skill-chip: var(--skillcat-speed); }
.skillcat-stamina { --skill-chip: var(--skillcat-stamina); }
.skillcat-twist { --skill-chip: var(--skillcat-twist); }
.skillcat-bracket { --skill-chip: var(--skillcat-bracket); }
.skillcat-tech { --skill-chip: var(--skillcat-tech); }

/* The owner's five badge families (docs/design/nuke-old-skill-categories.md §2): the granular
   piucenter vocabulary's identity colors, feeding the same --skill-chip variable the chip and
   bar rules already read, so a badge chip tints exactly like the rollup chips used to. */
.badgecat-brackets { --skill-chip: var(--badgecat-brackets); }
.badgecat-twists { --skill-chip: var(--badgecat-twists); }
.badgecat-staminaandruns { --skill-chip: var(--badgecat-staminaandruns); }
.badgecat-tech { --skill-chip: var(--badgecat-tech); }
.badgecat-doublestech { --skill-chip: var(--badgecat-doublestech); }

.tier-chart-card-skill[class*="badgecat-"],
.tier-chart-card-skill[class*="skillcat-"] {
    color: color-mix(in srgb, var(--skill-chip) 55%, var(--mix-ink));
    background: color-mix(in srgb, var(--skill-chip) 16%, transparent);
    border-color: color-mix(in srgb, var(--skill-chip) 45%, transparent);
}

.tier-chart-card-skill-more {
    opacity: .75;
}

.tier-table-skills .tier-chart-card-skill {
    margin-right: 3px;
}

/* Folder Stats: personal per-skill pass rates, weakest first (piucenter round 3).
   Rides the same --skill-chip category tint the chips use. */
.tier-folder-skills {
    margin-top: 8px;
}

.tier-folder-skills-title {
    display: block;
    color: var(--mix-ink-muted);
}

/* Bar + % = ability over played charts; the trailing count = completion (played /
   charts carrying the skill). Sorted by their product upstream. */
.tier-folder-skill-row {
    display: grid;
    grid-template-columns: 92px 1fr 38px 44px;
    align-items: center;
    gap: 8px;
    font-size: .75rem;
    padding: 1px 0;
}

.tier-folder-skill-label {
    color: color-mix(in srgb, var(--skill-chip) 60%, var(--mix-ink));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tier-folder-skill-track {
    height: 5px;
    border-radius: 3px;
    background: color-mix(in srgb, var(--skill-chip) 14%, transparent);
    overflow: hidden;
}

.tier-folder-skill-fill {
    display: block;
    height: 100%;
    border-radius: 3px;
    background: var(--skill-chip);
}

.tier-folder-skill-value {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.tier-folder-skill-count {
    text-align: right;
    color: var(--mix-ink-muted);
    font-size: .68rem;
    font-variant-numeric: tabular-nums;
}

.tier-chart-card-scoreline {
    display: block;
}

.lamp-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 8px 0;
}

.lamp-chip {
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 12px;
    padding: 2px 8px;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: .75rem;
}

.lamp-chip-meter {
    width: 48px;
    height: 4px;
    background: var(--mud-palette-lines-default);
    border-radius: 2px;
    overflow: hidden;
    display: inline-block;
}

.lamp-chip-fill {
    display: block;
    height: 100%;
    background: var(--mud-palette-primary);
}

.lamp-chip-complete .lamp-chip-fill {
    background: var(--mud-palette-success);
}

.border-legend {
    font-size: .75rem;
    color: var(--mud-palette-text-secondary);
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    margin: 8px 0;
}

.border-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.border-legend-swatch {
    width: 20px;
    height: 12px;
    display: inline-block;
    border: 2px solid var(--mud-palette-lines-default);
    border-radius: 3px;
}

/* The card border language (owner-locked): solid success = passed, dashed info = To-Do,
   dashed success = passed in another mix. Declared AFTER the card and swatch bases on
   purpose — those declare `border` shorthands at equal specificity, so source order is
   what guarantees the state classes win everywhere they're worn. */
.tier-chart-card-pass {
    border-color: var(--mud-palette-success);
    border-style: solid;
}

.tier-chart-card-todo {
    border-color: var(--mud-palette-info);
    border-style: dashed;
}

.tier-chart-card-other-mix {
    border-color: var(--mud-palette-success);
    border-style: dashed;
}

/* Played and broke. Grey rather than the pass green because the run earned nothing, and
   dotted rather than dashed so the three "we have seen you here" states stay separable at
   a glance. The mix token rather than a Mud palette entry: this is the only one of the
   four whose colour is a shade of the page rather than a semantic. */
.tier-chart-card-broken {
    border-color: color-mix(in srgb, var(--mix-ink-muted) 70%, transparent);
    border-style: dotted;
}

/* Randomizer draw states join the same source-order contract: held = mix-primary ring
   (deliberately NOT the pass-green), vetoed = error red — both in every density, on
   top of the dim/strike second channels. */
.draw-card-held {
    border-color: var(--mix-primary);
    border-style: solid;
    box-shadow: 0 0 0 1px var(--mix-primary), 0 0 14px var(--mix-glow);
}

.draw-card-vetoed {
    border-color: var(--mud-palette-error);
    border-style: solid;
}

.folder-picker {
    display: flex;
    align-items: center;
    gap: 2px;
}

.folder-picker-anchor {
    position: relative;
}

.folder-picker-pop {
    padding: 8px;
}

.folder-picker-types {
    margin-bottom: 8px;
}

.folder-picker-levels {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 2px;
    max-height: 260px;
    overflow-y: auto;
}

.folder-picker-level {
    background: none;
    border: none;
    border-radius: 4px;
    padding: 6px 0;
    cursor: pointer;
    font: inherit;
    color: var(--mud-palette-text-primary);
    text-align: center;
}

.folder-picker-level:hover {
    background: rgba(255, 255, 255, .08);
}

.folder-picker-current {
    color: var(--mud-palette-primary);
    font-weight: 600;
}

/* A folder this host has nothing for. Dimmed rather than hidden: the grid is a map of
   the level range, and holes in it are information — they say the change landed
   somewhere else. */
.folder-picker-level-off {
    opacity: .3;
    cursor: default;
}

.folder-picker-level-off:hover {
    background: none;
}

/* ===== Home dashboard (unlisted pre-release, D7): 4-column desktop grid, mobile
   derives a single column from auto-flow order (D3), cells span via size presets
   (D5). The widget frame is owned by WidgetHost so every widget wears identical
   chrome. ===== */

.dash-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 56px 16px;
    text-align: center;
}

.dash-pagebar {
    display: flex;
    gap: 4px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}

.dash-pagetab {
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px 14px;
    border-radius: 8px 8px 0 0;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: .95rem;
    letter-spacing: .05em;
    color: var(--mix-ink-muted);
    border-bottom: 2px solid transparent;
}

.dash-pagetab.active {
    color: var(--mix-ink);
    border-bottom-color: var(--mix-primary);
    text-shadow: 0 0 10px var(--mix-glow);
}

.dash-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: 168px;
    grid-auto-flow: row;
    gap: 14px;
}

.dash-cell {
    min-width: 0;
}

.dash-cols-2 { grid-column: span 2; }
.dash-cols-3 { grid-column: span 3; }
.dash-cols-4 { grid-column: span 4; }
.dash-rows-2 { grid-row: span 2; }

.dash-widget {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .06);
    border-radius: 10px;
    padding: 12px 14px;
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.dash-widget-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    flex: none;
}

.dash-widget-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: .82rem;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.dash-widget-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.dash-widget-message {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: var(--mix-ink-muted);
}

/* Import Scores widget (§4): a credential form has to live in a 1x1 body, so the fields and
   button pack into a tight flex column that scrolls rather than clipping the action off. */
.import-widget-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}

.import-widget-body .mud-input-control {
    margin-top: 0;
}

/* Saved-credential state: alert + full-width action, packed to the middle. */
.import-saved {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Spinner / done state: everything centered on both axes. */
.import-progress {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}

/* Typed one-time credentials: username/password stacked, a tall import button beside them. */
.import-typed {
    display: flex;
    gap: 6px;
    align-items: stretch;
}

.import-typed-fields {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.import-typed-go {
    min-width: 48px;
    height: auto;
}

/* Nav-bar import indicator: a pulsing dot on the avatar while a background import runs. */
.nav-avatar-wrap {
    position: relative;
    display: inline-flex;
}

.nav-import-pulse {
    position: absolute;
    top: -1px;
    right: -1px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--mix-primary);
    border: 1px solid var(--mix-surface);
    animation: nav-import-pulse 1.4s ease-out infinite;
}

@keyframes nav-import-pulse {
    0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mix-primary) 65%, transparent); }
    70% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--mix-primary) 0%, transparent); }
    100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mix-primary) 0%, transparent); }
}

/* Quick Record widget (§4.2): the arcade recorder, purpose-built to fit a 1x1 body. */
.qr-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.qr-hint {
    font-size: .68rem;
    color: var(--mix-ink-muted);
}

/* The selected chart — a display header, not a chip: nothing here navigates. */
.qr-selected {
    display: flex;
    align-items: center;
    gap: 7px;
}

.qr-mini-art {
    flex: none;
    display: inline-flex;
}

.qr-mini-art img {
    width: 22px;
    height: 22px;
    border-radius: 4px;
}

.qr-selected-name {
    flex: 1;
    min-width: 0;
    font-family: var(--font-display);
    letter-spacing: .03em;
    font-size: .9rem;
    color: var(--mix-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.qr-scorerow {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Score and the plate/result dropdown share the row (owner, 2026-07-13): score cut to
   ~half, plate lifted up beside it as shorthand. On the legacy row the score dominates and
   the letter-grade box stays compact (owner, field test). */
.qr-score-field {
    flex: 1 1 0;
    min-width: 96px;
}

/* Plate lives on the Save row (owner, 2026-07-13): compact on the left, Save pushed right. */
.qr-plate-field {
    flex: 0 1 auto;
    min-width: 104px;
    max-width: 168px;
}

/* The derived grade doubles as the broken toggle — click to flip pass/broken while keeping
   the plate (plated broken). Deliberately subtle: pointer + a hover tint, no label. */
.qr-grade-toggle {
    flex: none;
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    border-radius: 6px;
    padding: 2px;
}

.qr-grade-toggle:hover {
    background: rgba(255, 255, 255, .07);
}

.qr-actionrow {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Second row: plate on the left, Save pushed to the right (margin-left auto) so it never
   clips on narrow widths (the mobile bug). Pinned to the bottom of the body. */
.qr-actionrow-save {
    margin-top: auto;
}

.qr-actionrow-save .qr-save-btn {
    margin-left: auto;
}

/* MudBlazor fields carry generous default margins — reclaim them for the tight footprint. */
.qr-body .mud-input-control {
    margin-top: 0;
}

.qr-saved {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    gap: 12px;
}

.qr-saved-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.qr-saved-title {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: .13em;
    font-size: .74rem;
    color: var(--mud-palette-success);
}

.qr-saved-song {
    font-family: var(--font-display);
    font-size: 1rem;
    color: var(--mix-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.qr-saved-detail {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: .78rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.qr-saved-grade {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--mix-ink);
}

/* All-mixes mode: the runtime picker + the mix chip on the recording header. The chip is
   neutral (not the theme accent) so it doesn't imply the active theme is the record mix. */
.qr-mix-field {
    flex: none;
}

/* Legacy grade strip (owner, 2026-07-13): tap a grade image to pick it (passing), tap the
   selected one again to mark broken (its art goes cracked). Replaces the select + checkbox. */
/* The grade strip is the primary/lead row in legacy (score dropped below it); 4 primaries +
   a "more" menu, spread with a little air. */
.qr-graderow {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.qr-graderow-disabled {
    pointer-events: none;
    opacity: .5;
}

/* "More" overflow (B and lower) — either a … affordance or the selected lower grade. */
.qr-grade-more {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 26px;
    min-width: 26px;
    cursor: pointer;
    border-radius: 5px;
    color: var(--mix-ink-muted);
    font-size: 1.15rem;
    line-height: 1;
    opacity: .75;
}

.qr-grade-more:hover {
    opacity: 1;
    background: rgba(255, 255, 255, .06);
}

.qr-grade-menu-img {
    height: 24px;
    width: auto;
}

.qr-grade-opt {
    height: 30px;
    width: auto;
    cursor: pointer;
    border-radius: 5px;
    padding: 2px 3px;
    opacity: .5;
    transition: opacity .12s, transform .12s, background .12s;
}

.qr-grade-opt:hover {
    opacity: .85;
    background: rgba(255, 255, 255, .06);
}

.qr-grade-opt-sel {
    opacity: 1;
    background: color-mix(in srgb, var(--mix-primary) 22%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mix-primary) 55%, transparent);
    transform: scale(1.08);
}

.qr-mixchip {
    font-family: var(--font-display);
    font-size: .6rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--mix-ink-muted);
    background: var(--mix-surface-muted);
    border: 1px solid rgba(255, 255, 255, .08);
    padding: 1px 6px;
    border-radius: 5px;
    flex: none;
    max-width: 88px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Column stagger (round 3): 4 on desktop, 3 on small desktop/tablet, 2 on landscape
   phones, 1 on portrait phones. Spans clamp to the column count. */
@media (max-width: 1279.98px) {
    .dash-grid { grid-template-columns: repeat(3, 1fr); }

    .dash-cols-4, .dash-cols-3 { grid-column: span 3; }
}

@media (max-width: 959.98px) {
    .dash-grid { grid-template-columns: repeat(2, 1fr); }

    .dash-cols-4, .dash-cols-3, .dash-cols-2 { grid-column: span 2; }
}

@media (max-width: 599.98px) {
    .dash-grid {
        grid-template-columns: 1fr;
        grid-auto-rows: minmax(168px, auto);
    }

    .dash-cols-2, .dash-cols-3, .dash-cols-4 { grid-column: span 1; }

    .dash-rows-2, .dash-rows-3 { grid-row: span 1; }
}

/* Edit mode: toolbar, edit chrome, add-drawer. */

.dash-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}

.dash-toolbar .dash-pagebar {
    margin-bottom: 0;
}

.dash-pagetab-new {
    color: var(--mix-primary);
}

.dash-widget-editing {
    border-style: dashed;
    border-color: color-mix(in srgb, var(--mix-primary) 45%, transparent);
}

.dash-edit-controls {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    flex: none;
}

/* Header refresh action (shuffle etc.): first auto margin wins the free space, so it
   sits far right in browse mode and immediately left of the edit controls in edit. */
.dash-head-action {
    margin-left: auto;
    flex: none;
}

/* Widget-pushed title-bar content (§2.3 header slot) — e.g. Quick Record's selected chart.
   Sits at the right of the title; the mini-art/bubble/✕ line up compactly. */
.dash-head-slot {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    overflow: hidden;
}

.dash-head-slot .qr-mini-art img {
    width: 28px;
    height: 28px;
    border-radius: 4px;
}

/* Header-slot status glyph (e.g. Hot Streak's fallback note) — icon + tooltip only. */
.dash-head-flag {
    display: inline-flex;
    align-items: center;
    cursor: help;
}

.dash-drawer-body {
    padding: 16px;
}

.dash-drawer-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px;
    border-radius: 8px;
    cursor: pointer;
}

.dash-drawer-item:hover {
    background: rgba(255, 255, 255, .06);
}

.dash-drawer-item.disabled {
    opacity: .45;
    pointer-events: none;
}

.dash-chart-fill {
    flex: 1;
    min-height: 0;
}

/* Pumbility widget: stat block + scrollable target list with dismiss. */

.dash-pumbility {
    display: flex;
    gap: 16px;
    flex: 1;
    min-height: 0;
}

.dash-pumbility-left {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: none;
    max-width: 46%;
}

.dash-stat-num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 2.2rem;
    line-height: 1;
    color: var(--rarity-gold);
    font-variant-numeric: tabular-nums;
}

.dash-stat-delta {
    color: var(--mud-palette-success);
    font-size: .8rem;
    font-weight: 600;
}

.dash-sparkline {
    width: 100%;
    height: 26px;
}

.dash-muted {
    color: var(--mix-ink-muted);
}

.dash-pumbility-targets {
    flex: 1;
    min-width: 0;
    min-height: 0; /* flex-column children refuse to shrink without this — the tall variant could never scroll */
    display: flex;
    flex-direction: column;
    border-left: 1px solid rgba(255, 255, 255, .06);
    padding-left: 14px;
}

.dash-targets {
    flex: 1;
    min-height: 0;
}

.dash-target-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
    font-size: .8rem;
}

.dash-target-name {
    min-width: 0;
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-display);
    letter-spacing: .04em;
    color: var(--mix-ink-muted);
}

/* Suggested Charts only: a full-width single column shows the name to fill the gap the
   right-aligned score would leave, but a cramped narrow cell hands that width back to
   the score. Scoped to .dash-suggested's container so the always-named Weekly and Daily
   Step rows (which share this class but sit in no such container) keep their names. */
@container dash-suggested (max-width: 209.98px) {
    .dash-target-name { display: none; }
}

.dash-skillchip {
    font-size: .68rem;
    white-space: nowrap;
    flex: none;
}

.dash-target-gain {
    font-family: var(--font-display);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--mud-palette-success);
    flex: none;
}

/* Weekly widget: board rows + rotation countdown. */

.dash-weekly {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.dash-weekly-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 4px;
    flex: none;
}

.dash-countdown {
    font-family: var(--font-display);
    font-size: .7rem;
    letter-spacing: .08em;
    color: var(--mix-accent);
    border: 1px solid color-mix(in srgb, var(--mix-accent) 40%, transparent);
    border-radius: 10px;
    padding: 1px 8px;
    white-space: nowrap;
}

.dash-weekly-expiry {
    font-family: var(--font-display);
    font-size: .68rem;
    letter-spacing: .05em;
    color: var(--mix-ink-muted);
    flex: none;
}

.dash-weekly-place {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: .75rem;
    flex: none;
    font-variant-numeric: tabular-nums;
}

/* Community Highlights feed (docs/design/home-page-widgets.md §7). */
.dash-ch-feed {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    /* Never pans: overflow-y:auto forces this axis from visible to auto, so any
       too-long line would otherwise mint a horizontal scrollbar for the whole feed. */
    overflow-x: hidden;
    height: 100%;
    /* So win rows can respond to the widget's own width, not just the viewport. */
    container-type: inline-size;
}

.dash-ch-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
    text-align: center;
    padding: 1rem;
}

.rvl-feed-lead {
    margin: 14px 0 4px;
}

.rvl-cmp-folder {
    margin: 6px 0 10px;
}

/* The rail and its arrows. The native horizontal scrollbar is hidden on the desktop rail: it
   is chunky, it steals a row of height under the cards, and it is the only scrollbar on the
   page that runs sideways, so it reads as a stray control rather than a hint. The arrows
   replace it — they only render where the rail is actually horizontal. */
.rvl-rail-wrap {
    position: relative;
}

.dash-ch-feed.rvl-feed-rail {
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.dash-ch-feed.rvl-feed-rail::-webkit-scrollbar {
    display: none;
}

.rvl-rail-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    color: var(--mix-ink);
    background: color-mix(in srgb, var(--mix-surface) 88%, transparent);
    box-shadow: 0 1px 8px -2px rgba(0, 0, 0, .6);
}

.rvl-rail-arrow:hover {
    background: var(--mix-surface);
}

.rvl-rail-arrow.prev {
    left: -6px;
}

.rvl-rail-arrow.next {
    right: -6px;
}

/* Below the rail's own breakpoint the feed is a plain column, so a sideways arrow would
   scroll nothing. */
@media (max-width: 700px) {
    .rvl-rail-arrow {
        display: none;
    }
}

/* ── The rivals rail ───────────────────────────────────────────────────────────────────
   Same feed component, laid out as a strip. On the Rivals page the feed is the first thing
   above the fold, and a column there pushes the roster off screen to say what a strip says
   in one glance. Cards are fixed-width and snap, so a partially visible next card is what
   tells you the rail scrolls — no arrows, no scrollbar chrome to style.

   Below 700px it reverts to the column it already is: a horizontal scroller on a phone
   competes with the page's own vertical scroll and loses. */
.dash-ch-feed.rvl-feed-rail {
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    gap: 10px;
    height: auto;
    padding-bottom: 6px;
    scroll-snap-type: x proximity;
    overscroll-behavior-x: contain;
}

.dash-ch-feed.rvl-feed-rail > .dash-ch-entry {
    flex: 0 0 clamp(230px, 26vw, 310px);
    scroll-snap-align: start;
    border-bottom: 0;
    border-radius: 8px;
    padding: .55rem .6rem;
    background: color-mix(in srgb, var(--mix-ink-muted) 7%, transparent);
}

@media (max-width: 700px) {
    .dash-ch-feed.rvl-feed-rail {
        flex-direction: column;
        overflow-x: visible;
        overflow-y: auto;
        max-height: 340px;
    }

    .dash-ch-feed.rvl-feed-rail > .dash-ch-entry {
        flex: none;
    }
}

.dash-ch-entry {
    display: flex;
    gap: .6rem;
    /* Right side breathes: on a marked row the audience band paints the entry, and a
       score flush against the band's edge read as clipped (owner, field test). */
    padding: .55rem .5rem .55rem .25rem;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink-muted) 15%, transparent);
}

.dash-ch-avatar {
    flex: none;
    width: 2rem;
    height: 2rem;
}

.dash-ch-body {
    min-width: 0;
    flex: 1;
}

.dash-ch-head {
    display: flex;
    align-items: baseline;
    gap: .5rem;
}

.dash-ch-name {
    font-weight: 600;
    font-size: .85rem;
}

.dash-ch-time {
    margin-left: auto;
    font-size: .7rem;
    white-space: nowrap;
}

.dash-ch-wins {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    margin-top: .15rem;
}

.dash-ch-win {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
    font-size: .78rem;
}

.dash-ch-chart {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    min-width: 0;
}

.dash-ch-song {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 12rem;
}

/* Prose rows (titles, folders, level-ups) wrap; only the scored one-liner below
   pins its caption to a single line, and the narrow reflows release even that. */
.dash-ch-why {
    color: var(--mix-ink-muted);
    overflow-wrap: break-word;
    min-width: 0;
}

/* Scored win = one line on wide: chart (the song name truncates) + highlight, then a right-aligned
   grade/plate + score. The narrow queries below reflow it into a chart+score line and a subtitle. */
.dash-ch-win-scored {
    flex-wrap: nowrap;
    align-items: center;
    gap: .35rem;
}

.dash-ch-win-scored .dash-ch-why {
    white-space: nowrap;
}

/* The level-up row is a badge image plus text — centered as a unit, not baseline-hung. */
.dash-ch-lvlup {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
}

.dash-ch-win-scored .dash-ch-chart {
    min-width: 0; /* the song name ellipsises rather than shove the score off the line */
}

.dash-ch-score-right {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    padding-left: .4rem;
}

.dash-ch-score {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    padding-left: .25rem;
}

/* Narrow — a 1-wide widget (container query on the feed) or mobile, where the dashboard is one
   column (media query): hide the song name and drop the highlight onto its own subtitle line. */
@container (max-width: 340px) {
    .dash-ch-song { display: none; }
    .dash-ch-win-scored { flex-wrap: wrap; }
    .dash-ch-win-scored .dash-ch-score-right { order: 2; }
    .dash-ch-win-scored .dash-ch-why { order: 3; flex-basis: 100%; font-size: .72rem; white-space: normal; }
}

@media (max-width: 600px) {
    .dash-ch-song { display: none; }
    .dash-ch-win-scored { flex-wrap: wrap; }
    .dash-ch-win-scored .dash-ch-score-right { order: 2; }
    .dash-ch-win-scored .dash-ch-why { order: 3; flex-basis: 100%; font-size: .72rem; white-space: normal; }
}

/* Card-strip person divider (avatar + vertical name) — the community analog of the
   Suggested-Charts category divider, reusing that strip's card CSS + arrow pager. */
.dash-strip-person {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 2px 3px;
    min-width: 0;
}

.dash-strip-pname {
    writing-mode: vertical-rl;
    font-family: var(--font-display);
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .02em;
    max-height: 62px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--mix-ink);
}

.dash-strip-person.you .dash-strip-pname {
    color: var(--mix-primary);
}

/* A title or full-folder clear has no chart art — it reads as a centered text card. */
.dash-card-text {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: 3px;
}

.dash-card-emoji {
    font-size: 1.35rem;
    line-height: 1;
}

/* The cards/dividers are wrapped in MudTooltip, so its root is the strip's flex child —
   keep it a fixed-size item so the cards don't grow or shrink. */
.dash-card-strip > .mud-tooltip-root {
    flex: none;
    min-width: 0;
    display: inline-flex;
}

/* Drag chrome: handle (desktop pointer only), dragged-cell dim, insertion marker. */

.dash-drag-handle {
    cursor: grab;
    color: var(--mix-ink-muted);
    font-size: .9rem;
    user-select: none;
    touch-action: none;
    flex: none;
}

.dash-dragging {
    opacity: .35;
}

.dash-drop-target {
    outline: 2px dashed var(--mix-primary);
    outline-offset: 2px;
    border-radius: 10px;
}

.dash-json textarea {
    font-family: Consolas, monospace;
    font-size: .78rem;
}

@media (max-width: 959.98px) {
    .dash-drag-handle {
        display: none;
    }
}

/* Field-test round 1: 3-row spans, swap indicator, mini art, clickable rows,
   tall pumbility. */

.dash-rows-3 { grid-row: span 3; }

.dash-swap-target {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
    border-radius: 10px;
}

.dash-mini-art {
    flex: none;
    width: 24px;
    height: 24px;
    border-radius: 5px;
    overflow: hidden;
    display: inline-flex;
}

.dash-mini-art img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Suggested Charts widget: goal sections inside one scroll + a right-hand score column. */

.dash-suggested {
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* Its own inline size decides whether target rows show the song name. */
    container: dash-suggested / inline-size;
}

.dash-target-caption {
    padding-top: 6px;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-family: var(--font-display);
}

.dash-target-score {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-variant-numeric: tabular-nums;
    font-size: .75rem;
    /* Suggested rows drop the name at 1x2 — the score column right-aligns itself. */
    margin-left: auto;
}

.dash-target-detail {
    font-size: .7rem;
}

/* Card strips (suggested-charts field test): wide widgets read as compact chart cards
   scrolling horizontally, not tabled text. Hover-revealed pager arrows (clicks handled
   by dashboard-grid.js delegation); honest x-axis fades mirror the vertical ones. */

.dash-strips {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.dash-strip-wrap {
    position: relative;
    flex: none;
    min-width: 0;
}

.dash-card-strip {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
    /* Bottom padding keeps the score line off the widget edge (owner, round 6). */
    padding: 2px 2px 8px;
    mask-image: linear-gradient(to right,
        transparent 0,
        #000 var(--dash-fade-left),
        #000 calc(100% - var(--dash-fade-right)),
        transparent 100%);
}

.dash-card-strip::-webkit-scrollbar {
    display: none;
}

@property --dash-fade-left {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
}

@property --dash-fade-right {
    syntax: "<length>";
    inherits: false;
    initial-value: 20px;
}

@supports (animation-timeline: scroll()) {
    .dash-card-strip {
        animation: dash-strip-fades linear both;
        animation-timeline: scroll(self x);
    }

    @keyframes dash-strip-fades {
        0% {
            --dash-fade-left: 0px;
            --dash-fade-right: 20px;
        }

        10% {
            --dash-fade-left: 20px;
            --dash-fade-right: 20px;
        }

        90% {
            --dash-fade-left: 20px;
            --dash-fade-right: 20px;
        }

        100% {
            --dash-fade-left: 20px;
            --dash-fade-right: 0px;
        }
    }
}

.dash-strip-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 26px;
    height: 26px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .14);
    background: color-mix(in srgb, var(--mix-surface-muted) 88%, transparent);
    color: var(--mix-ink);
    cursor: pointer;
    display: grid;
    place-items: center;
    font-size: 15px;
    line-height: 1;
    opacity: 0;
    transition: opacity .15s;
}

.dash-widget:hover .dash-strip-arrow,
.dash-strip-arrow:focus-visible {
    opacity: .85;
}

.dash-strip-arrow-left {
    left: 2px;
}

.dash-strip-arrow-right {
    right: 2px;
}

/* Touch scrolls the strip directly — pager arrows are a pointer affordance. */
@media (hover: none) {
    .dash-strip-arrow {
        display: none;
    }
}

.dash-chart-card {
    /* Sized so art + name + score clear a 2x1 cell on desktop (owner, round 6). */
    flex: none;
    width: 76px;
    min-width: 0;
}

@media (max-width: 599.98px) {
    /* Mobile cells auto-grow — the roomier card reads better there. */
    .dash-chart-card {
        width: 86px;
    }
}

.dash-card-art {
    position: relative;
    width: 100%;
    aspect-ratio: 1;
    border-radius: 8px;
    overflow: hidden;
    background: var(--mix-surface-muted);
}

@media (min-width: 600px) {
    /* Desktop strip cells are fixed-height (168px rows): landscape-crop the art so
       name + score + detail all clear the cell (owner, round 7). Mobile cells
       auto-grow, so the square art stays there. */
    .dash-card-art {
        aspect-ratio: auto;
        height: 52px;
    }
}

/* Direct child only — the DifficultyBubble overlay nests its own img inside this box,
   and a blanket rule blew it up to full card size (owner, round 4). */
.dash-card-art > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.dash-card-bubble {
    position: absolute;
    left: 3px;
    bottom: 3px;
}

.dash-card-veto {
    position: absolute;
    top: 2px;
    right: 2px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--mix-surface) 78%, transparent);
}

.dash-card-name {
    margin-top: 3px;
    font-family: var(--font-display);
    font-size: .72rem;
    line-height: 1.25;
    letter-spacing: .03em;
    color: var(--mix-ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dash-card-score {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: .72rem;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.dash-card-detail {
    font-size: .65rem;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Category context inside a merged strip: a slim vertical label opens each group
   (owner, round 7 — "which flavor of Score Push is this?"). */
.dash-strip-divider {
    flex: none;
    writing-mode: vertical-rl;
    font-family: var(--font-display);
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding: 2px 1px;
    border-left: 1px solid rgba(255, 255, 255, .10);
}

.dash-clickable {
    cursor: pointer;
}

.dash-clickable:hover {
    background: rgba(255, 255, 255, .05);
    border-radius: 6px;
}

.dash-pumbility-tall {
    flex-direction: column;
    gap: 8px;
}

.dash-pumbility-tall .dash-pumbility-left {
    max-width: none;
    flex: none;
}

.dash-pumbility-tall .dash-pumbility-targets {
    border-left: none;
    padding-left: 0;
    border-top: 1px solid rgba(255, 255, 255, .06);
    padding-top: 8px;
}

/* Round 2: target rows get air (the tall/mobile variant was crushing lines). */

.dash-target-row {
    min-height: 34px;
    padding: 3px 0;
}

.dash-pumbility-tall .dash-target-row {
    padding: 5px 0;
}

.dash-mini-art {
    width: 26px;
    height: 26px;
}

@media (max-width: 599.98px) {
    /* Mobile cells auto-grow — let the page scroll instead of clipping rows. */
    .dash-targets {
        overflow-y: visible;
        mask-image: none;
        animation: none;
    }
}

.dash-endzone {
    box-shadow: inset 0 -3px 0 0 var(--mix-primary);
    border-radius: 10px;
}

.dash-pools {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    font-variant-numeric: tabular-nums;
}

/* Account Stats widget: glowy Pumbility + competitive level, then the closest matches. */
.dash-acct {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1;
    min-height: 0;
}

.dash-acct-stats {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: none;
}

.dash-acct-eyebrow {
    font-size: .6rem;
    text-transform: uppercase;
    letter-spacing: .1em;
    font-weight: 700;
    color: var(--mud-palette-text-disabled);
}

.dash-acct-cl-eyebrow {
    margin-top: 6px;
}

.dash-acct-hero {
    display: flex;
    align-items: center;
    gap: 16px;
}

/* The P2 level gem beside the total — a fixed square so a slow image load never
   reflows the hero. The negative margin eats the hero gap plus the art's own
   transparent frame, so gem and number read as one unit (owner, field test). */
.dash-acct-hero .pumbility-level-badge {
    flex: none;
    margin-right: -8px;
}

.dash-acct-total {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    flex: none;
}

/* S/D Pumbility pools stacked to the right of the big total (owner, field-test). */
.dash-acct-pools {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    font-size: .82rem;
    font-variant-numeric: tabular-nums;
}

.dash-acct-poolrow {
    display: flex;
    gap: 6px;
    align-items: baseline;
    white-space: nowrap;
}

.dash-acct-poolrow > span:first-child {
    font-weight: 600;
}

.dash-acct-poolnum {
    font-weight: 700;
}

.dash-acct-active {
    box-shadow: 0 2px 0 var(--mix-primary);
}

.dash-acct-matches {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    border-top: 1px solid rgba(255, 255, 255, .06);
    padding-top: 8px;
}

.dash-acct-mhead {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 6px;
}

.dash-acct-mlabel {
    font-size: .6rem;
    text-transform: uppercase;
    letter-spacing: .1em;
    font-weight: 700;
    color: var(--mud-palette-text-disabled);
}

.dash-acct-you {
    font-size: .72rem;
    color: var(--mud-palette-text-secondary);
    font-variant-numeric: tabular-nums;
}

.dash-acct-you b {
    color: var(--daily-you);
    font-weight: 700;
}

.dash-acct-mlist {
    display: flex;
    flex-direction: column;
    gap: 5px;
    overflow-y: auto;
    min-height: 0;
}

.dash-acct-who {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.dash-acct-av {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    object-fit: cover;
    flex: none;
}

.dash-acct-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.dash-acct-trail {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    white-space: nowrap;
}

.dash-acct-lvl {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.dash-acct-empty {
    font-size: .72rem;
    font-style: italic;
    color: var(--mud-palette-text-disabled);
    padding: 8px 4px;
    text-align: center;
}

.dash-acct-mixpill {
    font-size: .58rem;
    font-weight: 800;
    letter-spacing: .03em;
    padding: 1px 7px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--mix-primary) 16%, transparent);
    color: var(--mix-primary);
    border: 1px solid color-mix(in srgb, var(--mix-primary) 40%, transparent);
}

/* Daily Step widget (docs/design/daily-step.md): the shared daily chart as a leaderboard card. */

/* Row-highlight tokens, global so the leaderboard dialog can glow too: you (blue), community
   (green), rival (red). Mix-invariant like the judgment and lifebar groups — a rival reads as a
   rival in every theme.

   --daily-rival is NOT MixPalette.Error (#C72020): that one is too dark to read at 13% fill and
   already means "something went wrong". This sits clear of the Phoenix secondary orange
   (#FF6B35) too, so a rival never reads as a brand accent (docs/design/rivals.md D39). */
:root {
    --daily-you: #4bb8ff;
    --daily-community: #43dc86;
    --daily-rival: #FF3B5C;
}

/* ── Row highlighting, one utility set over four unrelated row layouts ──────────────────
   ONE GEOMETRY for every state: a tint plus a bar down each edge. Colour is the only variable,
   so the segmented row is not a special case — it is the same shape with a different colour at
   each end. Rings were the original treatment and are gone: at row height a 1.5px ring reads as
   a box drawn around the row, which fought the board's own grid, and it made the segmented row
   look like a different component rather than the same one carrying two states.
   .weekly-lb-row (flex), .dash-ch-entry (feed card), the challenge board rows and the rival
   roster row share no layout at all, so the treatment is applied OVER whichever they use rather
   than grown as a variant inside each family (docs/design/rivals.md §3.6).

   Precedence is you → both → rival → community: you always wins, and a rival who is also a
   clubmate is more interesting as both than as either. */
.is-rival {
    background: color-mix(in srgb, var(--daily-rival) 13%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-rival), inset -3px 0 0 var(--daily-rival);
}

/* The green half of the pair. The weekly board had its own community row style before this
   utility set existed (.weekly-lb-community) and keeps it; the feed card and roster families
   have no such ancestor, so without this rule they emit a class that styles nothing. */
.is-community {
    background: color-mix(in srgb, var(--daily-community) 13%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-community), inset -3px 0 0 var(--daily-community);
}

/* Split fill plus a left and a right edge bar. A two-tone border-image ring would read as
   segmented too, but it kills border-radius; this keeps the corners every other row has. */
.is-both {
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--daily-rival) 14%, transparent) 0 50%,
        color-mix(in srgb, var(--daily-community) 14%, transparent) 50% 100%);
    box-shadow: inset 3px 0 0 var(--daily-rival), inset -3px 0 0 var(--daily-community);
}

/* A board-only rival's score came from the last weekly sweep. The asterisk is the whole
   disclaimer — the footnote under the board carries the date (D27). */
.rival-official-mark {
    color: var(--mix-accent);
    font-weight: 700;
    cursor: help;
}

.dash-daily {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
}

.dash-daily-limbo {
    align-self: flex-start;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: .78rem;
    padding: 3px 8px;
    border-radius: 6px;
    border: 1px solid var(--mix-primary);
    color: var(--mix-primary);
}

.dash-daily-chart {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    padding-bottom: 2px;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.dash-daily-board {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-height: 0;
}

/* The taller sizes scroll the whole board; dash-scroll supplies the quiet themed scrollbar. */
.dash-daily-board.dash-scroll {
    overflow-y: auto;
    flex: 1 1 auto;
}

.dash-lb-row {
    display: grid;
    grid-template-columns: 28px 1fr auto;
    align-items: center;
    gap: 8px;
    padding: 5px 7px;
    border-radius: 7px;
    background: color-mix(in srgb, var(--mix-surface-muted) 55%, transparent);
    font-size: .82rem;
}

.dash-lb-place {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.dash-lb-who {
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dash-lb-score {
    display: flex;
    align-items: center;
    gap: 6px;
    justify-content: flex-end;
    font-variant-numeric: tabular-nums;
}

.dash-lb-pts {
    font-weight: 600;
}

.dash-lb-you {
    background: color-mix(in srgb, var(--daily-you) 15%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-you), inset -3px 0 0 var(--daily-you),
        0 0 12px -4px var(--daily-you);
}

.dash-lb-community {
    background: color-mix(in srgb, var(--daily-community) 13%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-community), inset -3px 0 0 var(--daily-community);
}

.dash-lb-divider {
    font-size: .62rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--mix-ink) 55%, transparent);
    padding: 4px 2px 1px;
}

/* Your row always sits below the scrolling board — the board takes the flex space and scrolls
   internally, so this stays anchored at the widget's bottom. */
.dash-lb-pinned {
    flex: none;
    padding-top: 4px;
    margin-top: 2px;
    border-top: 1px solid rgba(255, 255, 255, .1);
}

.dash-daily-controls {
    display: flex;
    justify-content: flex-end;
    gap: 2px;
}

/* 1x1 split: a short top-three (name + grade, score on hover) on the left, your standing on the right. */
.dash-daily-split {
    flex: 1;
    display: flex;
    gap: 8px;
    min-height: 0;
    align-items: stretch;
}

.dash-daily-top3 {
    flex: 1.15;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
}

.dash-top3-row {
    display: grid;
    grid-template-columns: 16px 1fr auto;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--mix-surface-muted) 50%, transparent);
    font-size: .78rem;
}

.dash-top3-place {
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.dash-top3-name {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: 600;
}

.dash-top3-grade {
    font-weight: 800;
    font-size: .72rem;
}

/* A place with no entrant yet — the rank still shows, the rest dashes out. */
.dash-top3-empty {
    opacity: .45;
}

.dash-daily-mine {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 8px;
    border-radius: 9px;
    text-align: center;
}

.dash-daily-mine-empty {
    background: color-mix(in srgb, var(--mix-surface-muted) 45%, transparent);
}

.dash-mine-label {
    font-size: .6rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    font-weight: 800;
    opacity: .85;
}

.dash-mine-rank {
    font-size: 1.6rem;
    font-weight: 800;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
}

.dash-mine-line {
    font-size: .74rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.weekly-lb-verified {
    font-size: 0.9rem;
    opacity: 0.75;
}

.weekly-lb-photo {
    /* An icon-button squeezed to text scale so the proof link sits inline with the name. */
    padding: 0 2px;
}

.weekly-lb-photo .mud-icon-root {
    font-size: 0.95rem;
}

.weekly-lb-legend {
    color: color-mix(in srgb, var(--mix-ink) 55%, transparent);
}

/* Weekly leaderboard dialog (round 3, option 1). */

.weekly-lb-title {
    display: flex;
    align-items: center;
    gap: 10px;
}

.weekly-lb-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 6px;
    border-radius: 6px;
}

.weekly-lb-row + .weekly-lb-row {
    border-top: 1px solid rgba(255, 255, 255, .05);
}

.weekly-lb-me {
    background: color-mix(in srgb, var(--daily-you) 15%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-you), inset -3px 0 0 var(--daily-you);
}

.weekly-lb-community {
    background: color-mix(in srgb, var(--daily-community) 13%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-community), inset -3px 0 0 var(--daily-community);
}

.weekly-lb-place {
    font-family: var(--font-display);
    font-weight: 700;
    min-width: 36px;
    font-variant-numeric: tabular-nums;
}

.weekly-lb-user {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===== Quiet scrolling (round 4): widget inner scrollers show NO scrollbar at rest —
   the edge fades are the "there's more" affordance. Desktop reveals a thin themed
   thumb on hover (hover = intent); touch keeps native auto-hiding overlays. Where
   scroll-driven animations exist, the fades are honest: top fade only once scrolled,
   bottom fade gone at the end. Elsewhere the static bottom fade remains. ===== */

@property --dash-fade-top {
    syntax: "<length>";
    inherits: false;
    initial-value: 0px;
}

@property --dash-fade-bottom {
    syntax: "<length>";
    inherits: false;
    initial-value: 24px;
}

.dash-scroll,
.dash-drawer .mud-drawer-content {
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
}

.dash-scroll:hover,
.dash-drawer .mud-drawer-content:hover {
    scrollbar-color: color-mix(in srgb, var(--mix-ink-muted) 35%, transparent) transparent;
}

.dash-scroll::-webkit-scrollbar,
.dash-drawer .mud-drawer-content::-webkit-scrollbar {
    width: 6px;
}

.dash-scroll::-webkit-scrollbar-track,
.dash-drawer .mud-drawer-content::-webkit-scrollbar-track {
    background: transparent;
}

.dash-scroll::-webkit-scrollbar-thumb,
.dash-drawer .mud-drawer-content::-webkit-scrollbar-thumb {
    background: transparent;
    border-radius: 3px;
}

.dash-scroll:hover::-webkit-scrollbar-thumb,
.dash-drawer .mud-drawer-content:hover::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--mix-ink-muted) 35%, transparent);
}

.dash-scroll {
    overflow-y: auto;
    mask-image: linear-gradient(to bottom,
        transparent 0,
        #000 var(--dash-fade-top),
        #000 calc(100% - var(--dash-fade-bottom)),
        transparent 100%);
}

@supports (animation-timeline: scroll()) {
    .dash-scroll {
        animation: dash-scroll-fades linear both;
        animation-timeline: scroll(self);
    }

    @keyframes dash-scroll-fades {
        0% {
            --dash-fade-top: 0px;
            --dash-fade-bottom: 24px;
        }

        10% {
            --dash-fade-top: 24px;
            --dash-fade-bottom: 24px;
        }

        90% {
            --dash-fade-top: 24px;
            --dash-fade-bottom: 24px;
        }

        100% {
            --dash-fade-top: 24px;
            --dash-fade-bottom: 0px;
        }
    }
}

/* Themed ApexCharts tooltips (round 5): Apex's own dark theme half-applies — pin the
   popover to our tokens instead. Keyed on the shared wrapper class so every graph on
   the site can adopt it (ApexChartTheming.WrapperClass). */

.themed-apex .apexcharts-tooltip {
    background: rgba(8, 12, 18, .94) !important;
    border: 1px solid rgba(255, 255, 255, .16) !important;
    color: #ffffff !important;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .5) !important;
}

.themed-apex .apexcharts-tooltip-title {
    background: rgba(255, 255, 255, .06) !important;
    border-bottom: 1px solid rgba(255, 255, 255, .1) !important;
    color: #ffffff !important;
    font-family: var(--font-display) !important;
}

/* All the tooltip text runs white — the token ink was too dim to read over the chart (owner). */
.themed-apex .apexcharts-tooltip-text,
.themed-apex .apexcharts-tooltip-text-y-label,
.themed-apex .apexcharts-tooltip-text-y-value,
.themed-apex .apexcharts-tooltip-text-label,
.themed-apex .apexcharts-tooltip-text-value,
.themed-apex .apexcharts-tooltip-y-group,
.themed-apex .apexcharts-tooltip-series-group {
    color: #ffffff !important;
}

/* ===== Chart details page (docs/design/chart-details-overhaul.md, mock R2) =====
   Answer -> evidence -> record -> onward. Static-SSR-ready: everything here styles from
   tokens; the sections that need a circuit are components (the Stage-3 islands). */

.chart-empty {
    max-width: 560px;
    margin: 32px auto;
    display: grid;
    gap: 10px;
}

.chart-empty-sub {
    color: var(--mix-ink-muted);
}

.chart-hero {
    display: grid;
    grid-template-columns: 300px 1fr;
    gap: 28px;
    align-items: start;
    padding: 18px 0 8px;
}

/* The jacket column: art, then your score in the nook beneath it. */
.chart-hero-jacket-col {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 300px;
    flex: none;
}

/* The chart you are on stays in its song's lineup, ringed rather than removed — taking it
   out made the row read as "the other ones" and hid where you sit in the ladder. */
.chart-hero-sibling-current {
    display: inline-flex;
    padding: 3px;
    border-radius: 10px;
    border: 1px solid var(--mix-primary);
    box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 45%, transparent);
}

.chart-section-credit {
    margin-top: 14px;
    font-size: .74rem;
    color: var(--mix-ink-muted);
}

.chart-jacket {
    position: relative;
    width: 300px;
    border-radius: 14px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, .10);
    background: var(--mix-surface);
    box-shadow: 0 18px 50px rgba(0, 0, 0, .5);
}

/* Scoped to the jacket wrapper, never `.chart-jacket .mud-image`: the difficulty bubble is
   a MudImage in this box too, and telling it to fill the frame made it 300px wide. */
.chart-jacket-art,
.chart-jacket-art .mud-image {
    width: 100%;
    height: auto;
    display: block;
}

.chart-jacket-video {
    width: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    display: block;
}

/* The jacket is the button, same as the shelf's cards — two ways to start a video on one
   page is one too many. The bubble stays outside it: it labels the art, it does not play. */
.chart-jacket-playable {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    position: relative;
}

/* Centred circle, revealed on hover — .chart-card-play's treatment at the hero's scale.
   pointer-events: none so the button underneath owns every pixel of the art. */
.chart-jacket-play {
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 62px;
    height: 62px;
    padding-left: 4px;
    border-radius: 99px;
    pointer-events: none;
    background: rgba(0, 0, 0, .8);
    border: 1px solid rgba(255, 255, 255, .2);
    color: #fff;
    opacity: .85;
    transform: scale(.94);
    transition: opacity .12s, transform .12s, background .12s, border-color .12s;
}

.chart-jacket-play::before {
    content: "";
    border-style: solid;
    border-width: 10px 0 10px 16px;
    border-color: transparent transparent transparent currentColor;
}

.chart-jacket-playable:hover .chart-jacket-play,
.chart-jacket-playable:focus-visible .chart-jacket-play {
    opacity: 1;
    transform: scale(1);
}

.chart-jacket-playable:hover .chart-jacket-play {
    background: rgba(0, 0, 0, .93);
    border-color: var(--mix-primary);
}

.chart-jacket-close {
    position: absolute;
    right: 12px;
    top: 12px;
    z-index: 4;
    cursor: pointer;
    font-weight: 600;
    font-size: .68rem;
    color: #fff;
    background: rgba(0, 0, 0, .8);
    border: 1px solid rgba(255, 255, 255, .2);
    border-radius: 99px;
    width: 24px;
    height: 24px;
    line-height: 1;
}

.chart-jacket-close:hover {
    border-color: var(--mix-primary);
}

.chart-jacket-bubble {
    position: absolute;
    right: 10px;
    top: 10px;
    filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .6));
}

.chart-hero-title {
    font-family: var(--font-display);
    font-size: 2.3rem;
    font-weight: 800;
    line-height: 1.05;
    margin: 0;
    text-wrap: balance;
}

.chart-hero-sub {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 8px;
    color: var(--mix-ink-muted);
    font-size: .9rem;
}

.chart-hero-siblings {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 10px;
}

.chart-hero-facts {
    display: flex;
    gap: 26px;
    flex-wrap: wrap;
    margin-top: 16px;
}

.chart-fact-value {
    display: block;
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.chart-fact-label {
    display: block;
    font-size: .68rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin-top: 1px;
}

.chart-verdict {
    margin-top: 16px;
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .10);
    border-left: 3px solid var(--mix-accent);
    border-radius: 12px;
    padding: 14px 17px;
}

.chart-verdict-head {
    font-size: 1.12rem;
    font-weight: 700;
    line-height: 1.35;
    text-wrap: balance;
}

.chart-verdict-sub {
    color: var(--mix-ink-muted);
    font-size: .86rem;
    margin-top: 5px;
    max-width: 62ch;
}

.chart-verdict-chips {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 11px;
}

.chart-verdict-chip {
    border: 1px solid;
    border-radius: 99px;
    font-size: .74rem;
    font-weight: 700;
    padding: 3px 11px;
    white-space: nowrap;
}

.chart-verdict-chip-muted {
    color: var(--mix-ink-muted);
    border-color: rgba(255, 255, 255, .22);
}

.chart-hero-actions {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 16px;
}

.chart-overline {
    display: block;
    font-size: .68rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    font-weight: 600;
}

.chart-section {
    margin: 26px 0;
}

.chart-section-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.chart-section-sub {
    color: var(--mix-ink-muted);
}

/* Your best + record inputs (the record island at Stage 3). */
/* One card in the hero's nook, not two panels down the page: your score is the first thing
   you look for, and recording is a mode of it rather than a separate destination. */
.chart-record {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .10);
    border-radius: 12px;
    padding: 14px 16px;
}

.chart-record-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.chart-record-edit {
    flex: none;
    color: var(--mix-ink-muted);
}

.chart-record-edit:hover {
    color: var(--mix-primary);
}

.chart-record-inputs {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 10px;
}

.chart-record-score {
    margin-top: 8px;
}

/* A legacy best is a grade icon with the era number beside it, when the player gave one.
   Tabular figures because the number is a measurement, not a label. */
.chart-record-legacy-score {
    margin-left: 8px;
    font-variant-numeric: tabular-nums;
    vertical-align: middle;
}

.chart-record-age, .chart-record-note {
    display: block;
    color: var(--mix-ink-muted);
    margin-top: 4px;
}

.chart-record-empty {
    color: var(--mix-ink-muted);
    margin-top: 8px;
}

/* ScoreJourneyList — shared by the chart page's record panel and the details dialog's
   History tab. It lives here rather than in the component's own <style> block because a
   style block only reaches the DOM on the renders that include it, and this component has
   two hosts. No flex-grow on the score: the grade icon sits beside the number rather than
   floating to the far right (owner, piucenter round 4). */
.score-journey {
    margin-top: 12px;
    border-top: 1px dashed rgba(255, 255, 255, .14);
    padding-top: 9px;
}

.score-journey-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
}

.score-journey-date {
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.score-journey-score {
    font-variant-numeric: tabular-nums;
}

.score-journey-empty {
    color: var(--mix-ink-muted);
}

.chart-record-row {
    display: grid;
    grid-template-columns: minmax(120px, 1fr) minmax(120px, 1fr);
    gap: 10px 12px;
    align-items: center;
    margin-top: 8px;
}

/* Evidence graph cards - sentence first, curve second. */
.chart-evidence {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

.chart-evidence-card {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .10);
    border-radius: 12px;
    padding: 13px 15px;
}

.chart-evidence-caption {
    font-size: .92rem;
    font-weight: 600;
    line-height: 1.4;
    margin: 4px 0 8px;
    max-width: 48ch;
}

.chart-evidence-empty {
    grid-column: 1 / -1;
    color: var(--mix-ink-muted);
}

.chart-skill-foot {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 8px;
    font-size: .78rem;
    color: var(--mix-ink-muted);
}

/* History band. */
.chart-timeline {
    display: flex;
    overflow-x: auto;
    padding-bottom: 4px;
}

.chart-timeline-node {
    flex: 1;
    min-width: 150px;
    position: relative;
    padding: 14px 18px 4px 0;
}

.chart-timeline-node::before {
    content: "";
    position: absolute;
    top: 21px;
    left: 0;
    right: 0;
    height: 2px;
    background: rgba(255, 255, 255, .18);
}

.chart-timeline-node::after {
    content: "";
    position: absolute;
    top: 16px;
    left: 0;
    width: 12px;
    height: 12px;
    border-radius: 99px;
    background: var(--mix-bg);
    border: 3px solid var(--mix-primary);
}

.chart-timeline-dim::after {
    border-color: var(--mix-ink-muted);
}

.chart-timeline-mix {
    margin-top: 22px;
    font-weight: 800;
    font-size: .92rem;
}

.chart-timeline-level {
    margin-top: 4px;
    font-size: .82rem;
    color: var(--mix-ink-muted);
}

.chart-timeline-delta {
    margin-left: 6px;
    color: var(--diff-hard);
    font-weight: 800;
}

/* The legend chips, still worn by the official chart-board dialog. The page's own
   leaderboard table is gone — chart details renders ChartLeaderboardScopes now, which
   brings the .weekly-lb-row vocabulary with it. */
.chart-lb-legend {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .74rem;
    color: var(--mix-ink-muted);
}

.chart-lb-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 3px;
}

.chart-lb-dot-community {
    background: var(--daily-community);
}

.chart-lb-dot-me {
    background: var(--daily-you);
    margin-left: 10px;
}

.chart-shelf-empty {
    color: var(--mix-ink-muted);
}

/* Similar-charts shelf - the internal link mesh. Three across, then two, then one; no
   density modes, because the card is sized around 16:9 art and that shape is the point. */
.chart-shelf {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}

/* The static card grid is the crawlable mesh; the interactive shelf renders the same cards
   plus its controls and marks its root data-island-ready the moment it connects, which
   hides the static copy. Both render real <a href> cards, so nothing reflows on handoff. */
.chart-shelf-wrap:has([data-island-ready]) .chart-shelf-static {
    display: none;
}

.chart-shelf-controls {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 12px;
}

.chart-shelf-sort {
    display: flex;
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 4px;
    overflow: hidden;
}

.chart-shelf-sort button {
    font-size: .75rem;
    color: var(--mix-ink-muted);
    background: transparent;
    border: 0;
    padding: 7px 12px;
    cursor: pointer;
    transition: color .12s, background .12s;
}

.chart-shelf-sort button + button {
    border-left: 1px solid rgba(255, 255, 255, .12);
}

.chart-shelf-sort button[aria-pressed="true"] {
    color: var(--mix-ink);
    background: var(--mix-surface-muted);
}

.chart-shelf-sort button:disabled {
    opacity: .4;
    cursor: not-allowed;
}

.chart-shelf-personal {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .75rem;
    color: var(--mix-ink-muted);
    cursor: pointer;
}

.chart-shelf-personal input {
    accent-color: var(--mix-primary);
    cursor: pointer;
}

.chart-shelf-personal:has(input:disabled) {
    opacity: .4;
    cursor: not-allowed;
}

.chart-shelf-addfilter {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .75rem;
    color: var(--mix-ink-muted);
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 4px;
    padding: 6px 10px;
    cursor: pointer;
    transition: color .12s, border-color .12s;
}

.chart-shelf-addfilter:hover:not(:disabled),
.chart-shelf-addfilter[aria-expanded="true"] {
    color: var(--mix-ink);
    border-color: var(--mix-primary);
}

.chart-shelf-addfilter:disabled {
    opacity: .4;
    cursor: not-allowed;
}

/* How many filters are on, when the panel that would show you is shut. */
.chart-shelf-fcount {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    font-size: .65rem;
    font-weight: 700;
    color: var(--mix-primary-contrast);
    background: var(--mix-primary);
}

.chart-shelf-filterpanel {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-bottom: 14px;
    padding: 14px;
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 6px;
}

.chart-shelf-ftoggles {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
}

.chart-shelf-ftoggles label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .75rem;
    color: var(--mix-ink-muted);
    cursor: pointer;
}

.chart-shelf-ftoggles input {
    accent-color: var(--mix-primary);
    cursor: pointer;
}

.chart-shelf-ftoggles label:has(input:checked) {
    color: var(--mix-ink);
}

.chart-shelf-funavailable {
    opacity: .4;
    cursor: not-allowed;
}

/* Below the line because it is not one of the four: it asks the opposite question rather
   than narrowing this one. */
.chart-shelf-fopposite {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .75rem;
    color: var(--mix-ink-muted);
    cursor: pointer;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, .08);
}

.chart-shelf-fopposite input {
    accent-color: var(--mix-primary);
    cursor: pointer;
}

.chart-shelf-fopposite:has(input:checked) {
    color: var(--mix-ink);
}

.chart-shelf-fopposite:has(input:disabled) {
    opacity: .4;
    cursor: not-allowed;
}

.chart-shelf-fapply {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

/* The count owns the row; the buttons sit at the end of it. */
.chart-shelf-fcompare {
    flex: 1 1 auto;
    font-size: .74rem;
    color: var(--mix-ink-muted);
}

.chart-shelf-fclear,
.chart-shelf-fgo {
    font-size: .75rem;
    border-radius: 4px;
    padding: 6px 14px;
    cursor: pointer;
    transition: opacity .12s;
}

.chart-shelf-fclear {
    color: var(--mix-ink-muted);
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .12);
}

.chart-shelf-fgo {
    color: var(--mix-primary-contrast);
    background: var(--mix-primary);
    border: 1px solid var(--mix-primary);
    font-weight: 600;
}

.chart-shelf-fclear:disabled,
.chart-shelf-fgo:disabled {
    opacity: .4;
    cursor: not-allowed;
}

/* Filters that ran, as against filters being chosen — read-only, because the panel
   above is where they change and two edit points would fight. */
.chart-shelf-fchipclear {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    background: transparent;
    border: 0;
    padding: 4px 6px;
    cursor: pointer;
    text-decoration: underline;
}

.chart-shelf-fchipclear:hover {
    color: var(--mix-primary);
}

.chart-shelf-hint,
.chart-shelf-reach {
    font-size: .74rem;
    color: var(--mix-ink-muted);
}

.chart-shelf-reach {
    margin-top: 10px;
}

.chart-shelf-filters {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}

.chart-shelf-fchip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .72rem;
    color: var(--mix-ink-muted);
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 4px;
    padding: 4px 4px 4px 8px;
}

.chart-shelf-fchip span {
    color: var(--mix-ink);
    font-weight: 600;
}


.chart-shelf-nearmiss {
    margin-top: 18px;
}

.chart-shelf-nearmiss > summary {
    cursor: pointer;
    color: var(--mix-ink-muted);
    font-size: .8rem;
    padding: 6px 0;
}

.chart-shelf-nearmiss > .chart-shelf {
    margin-top: 10px;
}

.chart-card {
    position: relative;
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .10);
    border-radius: 4px;
    transition: border-color .12s, background .12s;
}

.chart-card:hover {
    border-color: var(--mix-primary);
    background: var(--mix-surface-muted);
}

/* 16:9 from the start, so the video drops into the art's exact box: the card never
   changes height and the grid never jumps. The jacket is the play target; the link out
   is the icon by the name, so the two never fight over a pixel. */
.chart-card-art {
    position: relative;
    display: block;
    aspect-ratio: 16 / 9;
    margin: 10px 10px 0;
    /* Minus the 10px side margins, so the art stays inside the card. A dead `width: 100%`
       sat above this and never applied. */
    width: calc(100% - 20px);
    border-radius: 2px;
    background: rgba(0, 0, 0, .35);
    padding: 0;
    border: 0;
}

button.chart-card-art {
    cursor: pointer;
}

/* Scoped to the jacket wrapper, never `.chart-card-art img`: the bubble is an <img> in
   that box too, and telling it to fill the box makes it the size of the card. */
.chart-card-jacket,
.chart-card-jacket > * {
    display: block;
    width: 100%;
    height: 100%;
}

.chart-card-jacket img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 2px;
}

.chart-card-art-playing {
    overflow: hidden;
    border: 1px solid var(--mix-primary);
}

.chart-card-video {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

.chart-card-bubble {
    position: absolute;
    right: -6px;
    bottom: -8px;
    z-index: 3;
    filter: drop-shadow(0 2px 7px rgba(0, 0, 0, .6));
}

.chart-card-body {
    display: block;
    min-width: 0;
    padding: 12px 12px 12px;
}

.chart-card-title {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 9px;
}

.chart-card-title h3 {
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    margin: 0;
    font-weight: 600;
    font-size: .88rem;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The card's only <a>. Small, but a real link — the crawler follows this. */
.chart-card-golink {
    flex: none;
    display: inline-flex;
    align-items: center;
    color: var(--mix-primary);
    opacity: .65;
    transition: opacity .12s;
}

.chart-card-golink:hover,
.chart-card-golink:focus-visible {
    opacity: 1;
}

.chart-card-golink .mud-icon-root {
    font-size: .95rem;
}

.chart-card-pct {
    font-weight: 700;
    font-size: .8rem;
    color: var(--mix-primary);
    font-variant-numeric: tabular-nums;
}

.chart-card-meta {
    display: block;
    margin-top: 4px;
    font-size: .69rem;
    line-height: 1.5;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.chart-card-meta em {
    font-style: normal;
    color: var(--mix-ink);
}

.chart-card-meta i {
    font-style: normal;
    opacity: .45;
    padding: 0 4px;
}

.chart-card-wl {
    display: block;
    margin: 10px 0 5px;
    font-weight: 600;
    font-size: .56rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.chart-card-why {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
}

.chart-card-why b {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    font-weight: 500;
    font-size: .69rem;
    padding: 4px 6px;
    border-radius: 2px;
    color: var(--mix-ink);
    background: color-mix(in srgb, var(--mix-primary) 11%, transparent);
    border: 1px solid color-mix(in srgb, var(--mix-primary) 40%, transparent);
}

.chart-card-why b var {
    font-weight: 600;
    font-size: .62rem;
    font-style: normal;
    color: var(--mix-primary);
    font-variant-numeric: tabular-nums;
}

/* Intensity is a different KIND of reason and must not read as a skill. */
.chart-card-why-intensity {
    background: color-mix(in srgb, var(--mix-secondary) 11%, transparent) !important;
    border-color: color-mix(in srgb, var(--mix-secondary) 40%, transparent) !important;
}

.chart-card-why-intensity var {
    color: var(--mix-secondary) !important;
}

/* Mirrors the art's box so the button centres on the art without knowing its height.
   Transparent to the mouse, so the link underneath keeps the whole card as its target
/* Decoration: the whole jacket is the button, so this only says so. */
.chart-card-play {
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 50px;
    height: 50px;
    padding-left: 3px;
    border-radius: 99px;
    pointer-events: none;
    background: rgba(0, 0, 0, .8);
    border: 1px solid rgba(255, 255, 255, .2);
    color: #fff;
    opacity: 0;
    transform: scale(.88);
    transition: opacity .13s, transform .13s, background .13s, border-color .13s;
}

.chart-card-play::before {
    content: "";
    border-style: solid;
    border-width: 8px 0 8px 13px;
    border-color: transparent transparent transparent currentColor;
}

.chart-card-art-playable:hover .chart-card-play,
.chart-card-art-playable:focus-visible .chart-card-play {
    opacity: 1;
    transform: scale(1);
}

.chart-card-art-playable:hover .chart-card-play {
    background: rgba(0, 0, 0, .93);
    border-color: var(--mix-primary);
}

.chart-card-close {
    position: absolute;
    right: 15px;
    top: 15px;
    z-index: 4;
    cursor: pointer;
    font-weight: 600;
    font-size: .68rem;
    color: #fff;
    background: rgba(0, 0, 0, .8);
    border: 1px solid rgba(255, 255, 255, .2);
    border-radius: 2px;
    padding: 4px 6px;
}

.chart-card-close:hover {
    border-color: var(--mix-primary);
}

.chart-admin {
    margin: 26px 0 12px;
}

@media (max-width: 900px) {
    .chart-hero {
        grid-template-columns: 1fr;
    }

    .chart-jacket {
        width: min(300px, 100%);
    }

    .chart-hero-title {
        font-size: 1.7rem;
    }

    .chart-record, .chart-evidence {
        grid-template-columns: 1fr;
    }

    .chart-shelf {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 600px) {
    .chart-shelf {
        grid-template-columns: 1fr;
    }
}

/* ============================================================================
   Weekly Charts — the challenges hub (docs/design/weekly-charts-overhaul.md).
   A static-SSR page: --mix-* / semantic tokens only, no --mud-* (static-shell.md
   D5). The one island is the dialog host; these classes are pure layout + the
   two semantic ramps.
   ============================================================================ */

.challenge-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    margin: 14px 0 12px;
}

.challenge-head h1 {
    margin: 0;
}

.challenge-yourweek {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    font-size: 12.5px;
}

.challenge-chip {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 12px;
    padding: 2px 10px;
    color: var(--mix-ink);
    white-space: nowrap;
}

.challenge-chip b {
    color: var(--mix-accent);
    font-weight: 600;
}

.challenge-controls {
    margin-left: auto;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Native-details pickers (week, communities): no circuit, the shell's mix-picker precedent. */
.challenge-picker {
    position: relative;
}

.challenge-picker > summary {
    list-style: none;
    cursor: pointer;
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 6px;
    padding: 3px 10px;
    font-size: 12.5px;
    color: var(--mix-ink);
    user-select: none;
    white-space: nowrap;
}

.challenge-picker > summary::-webkit-details-marker {
    display: none;
}

.challenge-picker > summary::after {
    content: " \25BE";
    color: var(--mix-ink-muted);
}

.challenge-picker[open] > summary {
    border-color: var(--mix-primary);
}

.challenge-picker-menu {
    position: absolute;
    right: 0;
    z-index: 20;
    margin-top: 5px;
    min-width: 220px;
    max-height: 280px;
    overflow: auto;
    background: var(--mix-surface-muted);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 8px;
    padding: 6px;
    box-shadow: 0 8px 22px rgba(0, 0, 0, .5);
}

.challenge-picker-menu a,
.challenge-picker-menu label {
    display: block;
    padding: 5px 9px;
    border-radius: 5px;
    color: var(--mix-ink);
    text-decoration: none;
    font-size: 13px;
    cursor: pointer;
}

.challenge-picker-menu a:hover,
.challenge-picker-menu label:hover {
    background: rgba(255, 255, 255, .06);
}

.challenge-picker-menu a.on {
    color: var(--mix-accent);
}

.challenge-picker-apply {
    margin: 6px 4px 2px;
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
    border: 0;
    border-radius: 5px;
    padding: 3px 12px;
    font-weight: 600;
    cursor: pointer;
}

.challenge-section {
    margin: 18px 0;
}

.challenge-sect-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.challenge-sect-head h2 {
    margin: 0;
}

.challenge-sect-head .sub {
    color: var(--mix-ink-muted);
    font-size: 12.5px;
}

.challenge-sect-head .right {
    margin-left: auto;
    display: flex;
    gap: 6px;
    align-items: center;
}

/* ---- shared row bits ------------------------------------------------------ */
.challenge-lb-place {
    min-width: 1.7em;
    text-align: right;
    font-weight: 700;
}

.challenge-flag {
    font-size: 10.5px;
    opacity: .8;
    margin-right: 4px;
}

.challenge-empty {
    border: 1px dashed rgba(255, 255, 255, .12);
    border-radius: 10px;
    padding: 16px;
    text-align: center;
    color: var(--mix-ink-muted);
}

.challenge-empty a {
    color: var(--mix-accent);
}

.challenge-muted {
    color: var(--mix-ink-muted);
}

/* ---- daily step strip ----------------------------------------------------- */
.challenge-limbo-chip {
    background: var(--mix-secondary);
    color: var(--mix-bg);
    font-weight: 700;
    border-radius: 4px;
    padding: 0 7px;
    font-size: 11.5px;
    text-transform: uppercase;
    white-space: nowrap;
}

/* ---- buttons -------------------------------------------------------------- */
.challenge-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
    font-weight: 600;
    border: 0;
    border-radius: 6px;
    padding: 3px 11px;
    cursor: pointer;
    font-size: 12.5px;
    text-decoration: none;
    white-space: nowrap;
}

.challenge-btn.ghost {
    background: transparent;
    color: var(--mix-primary);
    border: 1px solid var(--mix-primary);
}

.challenge-iconbtn {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .12);
    color: var(--mix-ink-muted);
    border-radius: 4px;
    padding: 0 6px;
    cursor: pointer;
    font-size: 11.5px;
    line-height: 1.6;
}

.challenge-iconbtn:hover {
    color: var(--mix-ink);
    border-color: var(--mix-primary);
}

/* ---- weekly grid ---------------------------------------------------------- */
.challenge-gridbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

.challenge-gridbar h2 {
    margin: 0;
}

.challenge-filter-note {
    color: var(--mix-ink-muted);
    font-size: 12px;
}

.challenge-filter-note a {
    color: var(--mix-accent);
    text-decoration: none;
}

/* Density switcher, right-aligned (Tier Lists treatment). */
.challenge-den-group {
    margin-left: auto;
    display: flex;
    gap: 2px;
}

.challenge-den-btn {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .12);
    color: var(--mix-ink-muted);
    border-radius: 5px;
    width: 28px;
    height: 26px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.challenge-den-btn.on {
    color: var(--mix-primary);
    border-color: var(--mix-primary);
}

/* ── The week's grid, round-12 anatomy (§12): unsquished cards, top-3 + you, both ranking
   worlds shipped. Density keys on the grid's own data-density. ── */
.challenge-grid {
    display: grid;
    gap: 14px;
    /* Cap the comfortable grid at 6 columns: a wide monitor otherwise fits a 7th, and the
       weekly board's chart count divides cleanly by 6, so the 7th just orphans the last row.
       Each track is at least 280px but never narrower than a sixth of the row, so at most six
       ever fill the width — fewer when the row can't hold six at 280px. */
    grid-template-columns: repeat(auto-fill, minmax(max(280px, (100% - 5 * 14px) / 6), 1fr));
}

.challenge-grid.suggested-only .challenge-card[data-suggested="false"] {
    display: none;
}

/* The filter note follows the grid's state — both texts ship, :has() picks one. */
.challenge-main:has(.challenge-grid.suggested-only) .challenge-filter-note .when-all,
.challenge-main:not(:has(.challenge-grid.suggested-only)) .challenge-filter-note .when-filtered {
    display: none;
}

.challenge-card {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .06);
    border-radius: 10px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    position: relative;
}

.challenge-card[data-suggested="true"] {
    border-color: color-mix(in srgb, var(--mix-accent) 55%, transparent);
    box-shadow: 0 0 14px -8px var(--mix-accent);
}

.challenge-card-jacket {
    position: relative;
    aspect-ratio: 16 / 7.5;
    background-size: cover;
    background-position: center;
    display: block;
}

.challenge-card-bubble {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 2;
}

.challenge-card-body {
    padding: 8px 10px 6px;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.challenge-card-name {
    display: block;
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--mix-ink);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.challenge-card-line {
    display: grid;
    grid-template-columns: 26px 20px minmax(0, 1fr) auto;
    gap: 7px;
    align-items: center;
    font-size: 12.2px;
    white-space: nowrap;
    color: var(--mix-ink);
    padding: 2px 4px;
    border-radius: 6px;
}

.challenge-card-line .who {
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    color: var(--mix-ink-muted);
    font-weight: 600;
}

.challenge-card-line .score {
    justify-self: end;
}

.challenge-card-line.mine {
    background: color-mix(in srgb, var(--daily-you) 15%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-you), inset -3px 0 0 var(--daily-you),
        0 0 12px -4px var(--daily-you);
}

.challenge-card-line.mine .who {
    color: var(--mix-ink);
}

.challenge-card-line.unplayed {
    display: flex;
    color: color-mix(in srgb, var(--mix-ink-muted) 55%, transparent);
}

.challenge-card-foot {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 8px 7px;
    border-top: 1px solid rgba(255, 255, 255, .05);
    color: var(--mix-ink-muted);
    font-size: 11.5px;
    margin-top: auto;
}

.challenge-card-foot .spacer,
.challenge-gridbar .spacer,
.challenge-railhead .spacer,
.challenge-railfoot .spacer {
    flex: 1;
}

/* ── The two ranking worlds (M20). Default shows the overall head; .relevant-on swaps to the
   renumbered in-range head. Rows/counters carry .co (overall) and .cr (in-range) pairs. ── */
.challenge-card-line.w-r:not(.w-o) {
    display: none;
}

.relevant-on .challenge-card-line {
    display: none;
}

.relevant-on .challenge-card-line.w-r {
    display: grid;
}

.relevant-on .challenge-card-line.unplayed.w-r {
    display: flex;
}

.challenge-card .cr {
    display: none;
}

.relevant-on .challenge-card .co {
    display: none;
}

.relevant-on .challenge-card .cr {
    display: inline;
}

.relevant-on .challenge-card-line[data-inrange="false"]:not(.mine) {
    display: none;
}

/* Compact keeps one action: the count chip opens the board (tier-list corner-chip). */
.challenge-count-chip {
    display: none;
    position: absolute;
    right: 5px;
    bottom: 5px;
    z-index: 2;
    background: color-mix(in srgb, var(--mix-bg) 85%, transparent);
    color: var(--mix-ink);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: 999px;
    padding: 1px 8px;
    font-size: 10.5px;
    line-height: 1.6;
    cursor: pointer;
}

.challenge-count-chip:hover {
    border-color: var(--mix-primary);
    color: var(--mix-primary);
}

.challenge-grid[data-density="Compact"] {
    grid-template-columns: repeat(auto-fill, minmax(108px, 1fr));
    gap: 10px;
}

.challenge-grid[data-density="Compact"] .challenge-card-body,
.challenge-grid[data-density="Compact"] .challenge-card-foot {
    display: none;
}

.challenge-grid[data-density="Compact"] .challenge-card-jacket {
    aspect-ratio: 1 / 1;
}

.challenge-grid[data-density="Compact"] .challenge-count-chip {
    display: block;
}

/* Table renders jacket and bubble side by side (M19) — the tier-table pattern, never overlaid. */
.challenge-grid[data-density="Table"] {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.challenge-grid[data-density="Table"] .challenge-card {
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
}

.challenge-grid[data-density="Table"] .challenge-card-jacket {
    width: 76px;
    aspect-ratio: 16 / 9;
    border-radius: 6px;
    flex: none;
}

.challenge-grid[data-density="Table"] .challenge-card-bubble {
    position: static;
    order: 1;
}

.challenge-grid[data-density="Table"] .challenge-card-body {
    flex-direction: row;
    align-items: center;
    gap: 14px;
    padding: 0;
    order: 2;
}

.challenge-grid[data-density="Table"] .challenge-card-name {
    width: 170px;
    flex: none;
    font-size: .92rem;
}

.challenge-grid[data-density="Table"] .challenge-card-line {
    flex: 1;
    background: none;
    box-shadow: none;
}

/* Table is top-1 + you: every visible-world row after the first hides unless it's yours. */
.challenge-grid[data-density="Table"]:not(.relevant-on)
.challenge-card-line.w-o:not(.mine) ~ .challenge-card-line.w-o:not(.mine) {
    display: none;
}

.challenge-grid[data-density="Table"].relevant-on
.challenge-card-line.w-r:not(.mine) ~ .challenge-card-line.w-r:not(.mine) {
    display: none;
}

.challenge-grid[data-density="Table"] .challenge-card-foot {
    border: 0;
    margin: 0;
    padding: 0;
    order: 3;
}

.challenge-poollink {
    color: var(--mix-ink-muted);
    font-size: 12.5px;
    margin-top: 8px;
}

/* ── The rail layout (§12.1, M14/M22): boards left in widget chrome, the grid right.
   The collapse ladder: ≥1080 rail-left · 640–1080 rail 2-up above the grid · <640 single
   column in fold order Daily → This Week → Monthly. ── */
.challenge-layout {
    display: grid;
    grid-template-columns: 330px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
    margin-top: 12px;
}

.challenge-rail {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

.challenge-main {
    min-width: 0;
}

@media (max-width: 1079.98px) {
    .challenge-layout {
        grid-template-columns: 1fr;
    }

    .challenge-rail {
        display: grid;
        grid-template-columns: 1fr 1fr;
        align-items: start;
    }
}

@media (max-width: 639.98px) {
    .challenge-layout {
        display: flex;
        flex-direction: column;
    }

    .challenge-rail {
        display: contents;
    }

    .challenge-railcard#daily {
        order: 0;
    }

    .challenge-main {
        order: 1;
    }

    .challenge-railcard#monthly {
        order: 2;
    }
}

/* ── Rail cards: the homepage dash-widget chrome. ── */
.challenge-railcard {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .06);
    border-radius: 10px;
    padding: 12px 14px;
    min-width: 0;
}

.challenge-railcard.limbo {
    border-left: 3px solid var(--mix-secondary);
}

.challenge-railhead {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
}

.challenge-kicker {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.challenge-railchart {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 10px;
}

.challenge-rail-jacket {
    width: 44px;
    height: 44px;
    border-radius: 6px;
    background-size: cover;
    background-position: center;
    flex: none;
    display: block;
}

.challenge-railchart-id {
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.challenge-railchart-id .name {
    font-weight: 700;
    font-size: .98rem;
    color: var(--mix-ink);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.challenge-railchart-id .sub {
    font-size: .72rem;
    color: var(--mix-ink-muted);
}

.challenge-railsub {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    margin: -4px 0 8px;
}

.challenge-railfoot {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    font-size: .74rem;
    color: var(--mix-ink-muted);
}

.challenge-ghostbtn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .76rem;
    color: var(--mix-ink-muted);
    background: transparent;
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 6px;
    padding: 4px 10px;
    cursor: pointer;
    transition: color .12s, border-color .12s;
}

.challenge-ghostbtn:hover {
    color: var(--mix-accent);
    border-color: var(--mix-accent);
}

/* ── Rail leaderboard rows: place · avatar · name · (CL) · value. ── */
.challenge-lb {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.challenge-lb-row {
    display: grid;
    grid-template-columns: 24px 20px minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 8px;
    padding: 4px 7px;
    border-radius: 7px;
    font-size: .83rem;
}

/* The row group is mix-invariant by design, so these read --daily-* like every other board
   rather than the per-mix brand colour they used to. The ladder now emits .is-rival/.is-both
   onto these same rows, and two greens (or two blues) for one meaning on one board is worse
   than a board whose you-row is not brand-coloured. */
.challenge-lb-row.mine {
    background: color-mix(in srgb, var(--daily-you) 15%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-you), inset -3px 0 0 var(--daily-you),
        0 0 12px -4px var(--daily-you);
}

.challenge-lb-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    color: var(--mix-ink);
}

.challenge-lb-total {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--mix-accent);
}

.challenge-lb-divider {
    font-size: .62rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin: 6px 2px 2px;
}

.challenge-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.challenge-cl {
    font-size: .68rem;
    color: var(--mix-ink-muted);
    background: var(--mix-surface-muted);
    border-radius: 4px;
    padding: 1px 5px;
    font-variant-numeric: tabular-nums;
}

.challenge-mboard[hidden] {
    display: none;
}

/* ── The Phoenix 2 folder-title track (docs/design/pumbility-title-track.md): the glowy bar
   toward your next PUMBILITY title + one folder-aware caption, replacing the Phoenix 1 folder
   bars. --mix-* so it wears the mix accent, not a fixed green. ── */
.ptt {
    display: grid;
    gap: 10px;
    margin: 0 0 14px;
}

/* No card behind the bar — it sits directly on the page (owner call). */
.ptt-band {
    padding: 2px 2px 4px;
    display: grid;
    gap: 9px;
}

.ptt-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px;
}

/* The bar's top-left slot: the "from …" whisper, or the "serves" notifier on wider screens. */
.ptt-lead {
    display: flex;
    align-items: flex-end;
    min-width: 0;
    min-height: 1em;
}

.ptt-from {
    font-family: var(--font-display);
    font-size: 13px;
    letter-spacing: .02em;
    color: var(--mix-ink-muted);
    min-height: 1em;
}

/* The compact "serves" notifier riding the top-left of the bar (wide screens only — see the
   breakpoint by .ptt-serves). Mirrors the banner's accent tint at chip scale. */
.ptt-serves-top {
    display: none;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 3px 9px;
    border-radius: 8px;
    font-family: var(--font-display);
    font-size: 12px;
    letter-spacing: .02em;
    white-space: nowrap;
    color: var(--mix-ink);
    border: 1px solid color-mix(in srgb, var(--mix-accent) 38%, transparent);
    background: color-mix(in srgb, var(--mix-accent) 12%, transparent);
}

.ptt-target {
    text-align: right;
    line-height: 1.02;
}

.ptt-k {
    display: block;
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: .16em;
    font-size: 9.5px;
    color: var(--mix-primary);
    font-weight: 600;
    margin-bottom: 1px;
}

.ptt-t {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 20px;
    letter-spacing: .02em;
    color: var(--mix-ink);
}

/* The glowy bar. overflow:visible so the ring's shadow reads; the fill and dot both carry the
   mix glow. */
.ptt-bar {
    position: relative;
    height: 18px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--mix-bg) 55%, #000);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    overflow: visible;
}

.ptt-fill {
    position: absolute;
    inset: 1px auto 1px 1px;
    border-radius: 9px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--mix-primary) 68%, #000), var(--mix-primary));
    box-shadow: 0 0 16px -3px var(--mix-primary);
}

.ptt-you {
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--mix-bg);
    border: 2.5px solid var(--mix-primary);
    box-shadow: 0 0 0 3px var(--mix-bg), 0 0 13px -1px var(--mix-primary);
}

/* The one caption where the Phoenix 1 percentage used to be. */
.ptt-cap {
    text-align: center;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 14.5px;
    letter-spacing: .02em;
    color: var(--mix-primary);
}

/* Grade-up is a bigger ask than volume, so it reads neutral rather than the encouraging accent. */
.ptt-cap-grade {
    color: var(--mix-ink);
}

/* The folder sits above your current title — you can push past it here. This is the phone
   placement (a banner under the bar); above ~480 it moves up to the top-left .ptt-serves-top chip. */
.ptt-serves {
    display: flex;
    align-items: center;
    gap: 9px;
    border-radius: 10px;
    padding: 8px 13px;
    font-size: 13px;
    border: 1px solid color-mix(in srgb, var(--mix-accent) 40%, transparent);
    background: color-mix(in srgb, var(--mix-accent) 12%, transparent);
    color: var(--mix-ink);
}

@media (min-width: 481px) {
    .ptt-serves-top { display: inline-flex; }
    .ptt-serves { display: none; }
}

.ptt-serves-ic {
    color: var(--mix-accent);
    flex: none;
    font-size: 13px;
}

/* The collapsed state: the folder is beneath your top 50, so the bar's gone — the serves whisper
   is all that remains. */
.ptt-behind {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 14px;
    font-family: var(--font-display);
    font-size: 14px;
    letter-spacing: .02em;
    color: var(--mix-ink-muted);
    background: color-mix(in srgb, var(--mix-surface) 55%, transparent);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 10px;
}

.ptt-behind-ic {
    flex: none;
    font-size: 15px;
}

/* ── The tier-list segment row (M18): joined buttons, filled primary when active. ── */
.challenge-seg {
    display: inline-flex;
    margin-bottom: 10px;
}

.challenge-seg-btn {
    font-size: .74rem;
    font-weight: 600;
    border: 1px solid color-mix(in srgb, var(--mix-primary) 55%, transparent);
    background: transparent;
    color: var(--mix-primary);
    padding: 3px 12px;
    cursor: pointer;
    margin-left: -1px;
    transition: background .12s, color .12s;
}

.challenge-seg-btn:first-child {
    border-radius: 6px 0 0 6px;
    margin-left: 0;
}

.challenge-seg-btn:last-child {
    border-radius: 0 6px 6px 0;
}

.challenge-seg-btn:hover {
    background: color-mix(in srgb, var(--mix-primary) 14%, transparent);
}

.challenge-seg-btn.on {
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
}

/* ── The relevant-players switch (M20) — deliberately quiet. ── */
.challenge-switch {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: .72rem;
    color: var(--mix-ink-muted);
    cursor: pointer;
    user-select: none;
    opacity: .85;
}

.challenge-switch:hover {
    opacity: 1;
}

.challenge-switch input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.challenge-switch i {
    width: 30px;
    height: 16px;
    border-radius: 999px;
    background: var(--mix-surface-muted);
    border: 1px solid rgba(255, 255, 255, .14);
    position: relative;
    transition: background .12s;
    flex: none;
}

.challenge-switch i::after {
    content: "";
    position: absolute;
    top: 1px;
    left: 1px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--mix-ink-muted);
    transition: left .12s, background .12s;
}

.challenge-switch input:checked + i {
    background: color-mix(in srgb, var(--mix-primary) 45%, var(--mix-surface-muted));
}

.challenge-switch input:checked + i::after {
    left: 15px;
    background: var(--mix-primary);
}

.challenge-switch input:focus-visible + i {
    outline: 2px solid var(--mix-primary);
    outline-offset: 1px;
}

/* ── Field-test round 1 ── */

/* The show-all/show-suggested toggles are actions, not text. */
.challenge-filter-note a {
    cursor: pointer;
}

/* Grade art and the score numeral center on one line and never wrap mid-row. */
.challenge-card-line .score,
.challenge-lb-score {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
    justify-self: end;
}

.challenge-card-line .score .mud-typography,
.challenge-lb-score .mud-typography {
    vertical-align: baseline !important;
}

/* Card mini-boards rank with a literal #N — one quiet color, no rarity ramp (the colored
   1s read as meaning; the ramp stays on the big boards where percentile is real). */
.challenge-card-line .challenge-lb-place {
    color: var(--mix-ink-muted);
    font-size: 11px;
    text-align: right;
}

.challenge-card-line.mine .challenge-lb-place {
    color: var(--mix-ink);
}

/* Shared-community rows glow green (the homepage widgets' treatment), you glow blue. */
.challenge-lb-row.community,
.challenge-card-line.community {
    background: color-mix(in srgb, var(--daily-community) 13%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-community), inset -3px 0 0 var(--daily-community);
}

.challenge-monthly tr.community td {
    background: color-mix(in srgb, var(--daily-community) 10%, transparent);
}

.challenge-monthly tr.community td:first-child {
    box-shadow: inset 3px 0 0 var(--daily-community);
}

.challenge-monthly tr.community td:last-child {
    box-shadow: inset -3px 0 0 var(--daily-community);
}

/* UserLabel inside board rows: flag + name on one truncating line. */
.challenge-lb-name,
.challenge-card-line .who {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    overflow: hidden;
}

/* Record dialog: score, live grade, and plate share a row; stacked again on narrow phones. */
.challenge-record-row {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.challenge-iconbtn.rec:hover {
    color: var(--mix-primary);
    border-color: var(--mix-primary);
}

.challenge-iconbtn.tro:hover {
    color: var(--mix-accent);
    border-color: var(--mix-accent);
}

/* ── The monthly dialog's counted-score stickers (M21): the official-leaderboards compact
   pattern, board-sized — jacket, bubble, grade/score strip, points badge. No song names. ── */
.challenge-mrow-who {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.challenge-stik-row {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}

.challenge-stik-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 6px;
    background: var(--mix-surface-muted);
    border-radius: 8px;
    padding: 10px;
    margin-top: 6px;
}

.challenge-stik {
    position: relative;
    display: block;
    width: 96px;
    aspect-ratio: 1 / 1;
    border-radius: 7px;
    overflow: hidden;
}

.challenge-stik-row .challenge-stik {
    width: 44px;
    aspect-ratio: 1 / 1;
}

.challenge-stik-row .challenge-stik .challenge-stik-line {
    display: none;
}

.challenge-stik-j {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
}

.challenge-stik-bubble {
    position: absolute;
    top: 4px;
    left: 4px;
    z-index: 2;
}

.challenge-stik-line {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    gap: 4px;
    background: color-mix(in srgb, var(--mix-bg) 85%, transparent);
    padding: 2px 5px;
    font-size: .64rem;
    z-index: 2;
}

.challenge-stik-line b {
    margin-left: auto;
    color: var(--mix-accent);
    font-variant-numeric: tabular-nums;
}

.challenge-poollink a {
    color: var(--mix-accent);
}

/* ---- monthly board -------------------------------------------------------- */
.challenge-monthly {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    min-width: 620px;
}

.challenge-monthly th {
    text-align: left;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-size: 12px;
    color: var(--mix-ink-muted);
    padding: 6px 10px;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
    background: var(--mix-surface);
}

.challenge-monthly td {
    padding: 5px 10px;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
    vertical-align: middle;
}

.challenge-monthly tr:last-child td {
    border-bottom: 0;
}

.challenge-monthly tr.mine td {
    background: color-mix(in srgb, var(--daily-you) 10%, transparent);
}

.challenge-monthly tr.mine td:first-child {
    box-shadow: inset 3px 0 0 var(--daily-you);
}

.challenge-monthly tr.mine td:last-child {
    box-shadow: inset -3px 0 0 var(--daily-you);
}

.challenge-mono-place {
    font-weight: 700;
    font-size: 15px;
}

.challenge-total {
    font-weight: 700;
    font-size: 15px;
    color: var(--mix-accent);
}

.challenge-expand > summary {
    cursor: pointer;
    color: var(--mix-primary);
    list-style: none;
}

.challenge-expand > summary::-webkit-details-marker {
    display: none;
}

.challenge-expand > summary::after {
    content: " \25B8";
}

.challenge-expand[open] > summary::after {
    content: " \25BE";
}

.challenge-expand-body {
    display: flex;
    gap: 7px;
    flex-wrap: wrap;
    padding: 7px 2px 2px;
}

/* ---- daily history -------------------------------------------------------- */
.challenge-history {
    display: flex;
    flex-direction: column;
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 9px;
    overflow: hidden;
}

.challenge-hist-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 5px 12px;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
    font-size: 13px;
    background: var(--mix-surface);
}

.challenge-hist-row:nth-child(even) {
    background: var(--mix-surface-muted);
}

.challenge-hist-row:last-child {
    border-bottom: 0;
}

.challenge-hist-date {
    color: var(--mix-ink-muted);
    min-width: 58px;
}

.challenge-hist-chart {
    display: flex;
    align-items: center;
    gap: 7px;
    flex: 1;
    min-width: 0;
}

.challenge-hist-chart a {
    color: var(--mix-ink);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.challenge-limbo-tag {
    background: var(--mix-secondary);
    color: var(--mix-bg);
    font-size: 9.5px;
    font-weight: 700;
    border-radius: 3px;
    padding: 0 5px;
    text-transform: uppercase;
}

.challenge-hist-place {
    min-width: 74px;
    text-align: right;
}

.challenge-hist-score {
    min-width: 118px;
    display: flex;
    justify-content: flex-end;
}

/* ---- legend --------------------------------------------------------------- */
.challenge-legend {
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: 9px;
    padding: 12px 15px;
}

.challenge-legend h3 {
    margin: 0 0 6px;
    font-size: 1rem;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    letter-spacing: .06em;
}

.challenge-ladder {
    display: grid;
    grid-template-columns: auto auto;
    gap: 1px 14px;
    font-size: 13px;
    align-items: center;
}

.challenge-rules {
    max-width: 42ch;
    color: var(--mix-ink-muted);
    font-size: 12.5px;
    margin: 0;
    padding-left: 18px;
}

.challenge-rules li {
    margin-bottom: 4px;
}

/* ---- mobile dock (jump links + reset countdown) --------------------------- */
.challenge-dock {
    display: flex;
    gap: 14px;
    align-items: center;
    font-size: 13px;
}

.challenge-dock a {
    color: var(--mix-ink);
    text-decoration: none;
    text-transform: uppercase;
}

.challenge-dock .reset {
    margin-left: auto;
    color: var(--mix-ink-muted);
    font-size: 12px;
}

/* /UploadPhoenixScores - the manual-import expander's numbered steps. */
.import-manual-steps {
    margin: 0;
    padding-left: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* ============================================================
   The 404 page - "your path was a MISS" (Pages/NotFound.razor).
   The title-screen image is the hero; the judgment slams over
   its lower edge like the in-game MISS flash. Judgment red is
   semantic (a judgment, not the mix accent); the credit counter
   mirrors the arcade credit line in the source frame.
   ============================================================ */
.nf-eyebrow {
    text-align: center;
    font-size: .68rem;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin: 28px 0 14px;
}

.nf-stage {
    position: relative;
    max-width: 860px;
    margin: 0 auto;
}

.nf-frame {
    display: block;
    width: 100%;
    border-radius: 10px;
    box-shadow: 0 30px 80px -20px rgba(196, 15, 61, .45);
}

.nf-judgment {
    position: relative;
    /* Only the MISS's top ~20% rides over the frame — any deeper covers the title text. */
    margin-top: clamp(-26px, -3vw, -12px);
    text-align: center;
    pointer-events: none;
}

.nf-miss {
    display: block;
    font-family: Impact, "Arial Black", sans-serif;
    font-style: italic;
    font-size: clamp(4.2rem, 15vw, 8.5rem);
    line-height: .92;
    letter-spacing: .04em;
    transform: skewX(-8deg) rotate(-2deg);
    background: linear-gradient(180deg, #ff8f9f 4%, #ff2f4e 42%, #a30822 96%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    filter: drop-shadow(0 0 22px rgba(255, 47, 78, .55)) drop-shadow(0 6px 0 rgba(20, 2, 8, .9));
}

@media (prefers-reduced-motion: no-preference) {
    .nf-miss {
        animation: nf-slam .34s cubic-bezier(.2, 1.6, .35, 1) .18s both;
    }

    @keyframes nf-slam {
        0% { opacity: 0; transform: skewX(-8deg) rotate(-2deg) scale(1.9); }
        70% { opacity: 1; transform: skewX(-8deg) rotate(-2deg) scale(.96); }
        100% { opacity: 1; transform: skewX(-8deg) rotate(-2deg) scale(1); }
    }
}

.nf-explain {
    max-width: 46ch;
    margin: 18px auto 0;
    text-align: center;
    color: var(--mix-ink-muted);
    font-size: .95rem;
    line-height: 1.55;
    text-wrap: balance;
}

.nf-actions {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 26px;
}

.nf-credit {
    margin: clamp(36px, 7vh, 64px) 0 24px;
    text-align: center;
    font-family: Consolas, "Courier New", monospace;
    font-size: .8rem;
    letter-spacing: .3em;
    color: #ffd94d;
    text-shadow: 0 0 12px rgba(255, 217, 77, .35);
}

/* ===== Charts SRP (docs/design/charts-srp.md) ================================
   The page stack: header (title + scope) → query chips → answer line → results.
   Tokens only — the two ramps and --mix-* carry every color. */
.srp-head {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}

.srp-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    min-height: 34px;
}

/* An applied-filter token is dismissed occasionally rather than hunted for, so it sits a
   little under the drawer chips' 40px — but its ✕ is still a real target, not a 16px icon. */
.srp-chip {
    min-height: 36px;
    font-size: .8rem;
}

    .srp-chip .mud-chip-close-button {
        width: 28px;
        height: 28px;
        margin-left: 2px;
    }

        .srp-chip .mud-chip-close-button .mud-icon-root {
            font-size: 1.1rem;
        }

.srp-chip-sort {
    border-color: var(--mix-accent) !important;
}

/* The count and the controls. Six targets plus the count are wider than a phone, so the
   row wraps — the controls stay one block, right-aligned, and drop to their own line
   rather than pushing the page sideways. */
.srp-answer {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin: 4px 0 12px;
}

.srp-answer-controls {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.srp-count {
    font-variant-numeric: tabular-nums;
}

.srp-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
    gap: 12px;
}

.srp-pager {
    display: flex;
    justify-content: center;
    margin: 18px 0 8px;
}

.srp-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 48px 0;
    color: var(--mix-ink-muted);
}

/* min-width:0 is load-bearing, not tidying. A grid item's automatic minimum size is its
   MIN-CONTENT width, and the card's title is `nowrap` — so one long song name ("Extreme
   Music School 2nd period feat. Nanahira", 482px) floored the whole column at its width,
   stretched every other card to match, and scrolled the page sideways. Letting the card
   shrink is also what lets the title's ellipsis do its job. */
.srp-card {
    position: relative;
    display: flex;
    min-width: 0;
    gap: 12px;
    background: var(--mix-surface);
    border: 1px solid var(--mix-surface-muted);
    border-radius: 10px;
    padding: 12px;
    transition: border-color .15s, box-shadow .15s;
}

.srp-card:hover,
.srp-card:focus-within {
    border-color: var(--mix-primary);
    box-shadow: 0 0 14px var(--mix-glow);
}

.srp-card-link {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: 10px;
}

.srp-card-art {
    flex: 0 0 auto;
}

.srp-card-main {
    flex: 1;
    min-width: 0;
}

.srp-card-title {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.srp-card-song {
    font-weight: 600;
    font-size: 1.05rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.srp-card-songtype {
    font-size: .7rem;
    color: var(--mix-ink-muted);
    white-space: nowrap;
}

.srp-card-artist {
    font-size: .75rem;
    color: var(--mix-ink-muted);
}

.srp-card-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 6px;
    align-items: center;
}

.srp-card-tier {
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .03em;
    border: 1px solid;
    border-radius: 5px;
    padding: 1px 7px;
    white-space: nowrap;
}

.srp-card-facts {
    margin-top: 7px;
    font-size: .72rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    display: flex;
    flex-wrap: wrap;
    gap: 3px 10px;
}

.srp-card-fact-lead {
    color: var(--mix-ink);
    font-weight: 600;
}

.srp-card-my {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
    min-width: 70px;
    text-align: right;
}

.srp-card-unplayed {
    font-size: .7rem;
    color: var(--mix-ink-muted);
    border: 1px dashed var(--mix-surface-muted);
    border-radius: 4px;
    padding: 2px 7px;
}

.srp-card-plate {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .05em;
}

.srp-card-score {
    font-size: .75rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.srp-card-actions {
    position: absolute;
    right: 8px;
    bottom: 6px;
    z-index: 2;
    display: flex;
    gap: 2px;
}

.srp-drawer {
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.srp-drawer-head {
    display: flex;
    align-items: center;
}

.srp-drawer-range {
    display: flex;
    gap: 10px;
}

/* The bottom way out, separated from the last facet so it doesn't read as one more
   filter. */
.srp-drawer-foot {
    border-top: 1px solid var(--mix-surface-muted);
    padding-top: 12px;
}

@media (max-width: 600px) {
    /* minmax(0, …), not a bare 1fr: `1fr` is minmax(auto, 1fr) and that `auto` floors the
       track at the widest card's min-content, which is how the one-column phone layout
       ended up wider than the phone. */
    .srp-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .srp-head {
        gap: 12px;
    }
}

/* The bottom nav outranks the drawer, so the drawer's close button has to clear it —
   only where the nav exists (the same Md seam the shell uses). */
@media (max-width: 959.98px) {
    .srp-drawer-foot {
        padding-bottom: calc(var(--bottom-nav-h) + 12px);
    }
}

/* SRP card state borders — the tier lists' owner-locked language */
.srp-card-pass {
    border-color: var(--mud-palette-success);
}

.srp-card-todo {
    border-style: dashed;
    border-color: var(--mud-palette-info);
}

.srp-head-mix {
    color: var(--mix-ink-muted);
    font-size: .9rem;
    letter-spacing: .04em;
    text-transform: uppercase;
}

/* SRP drawer: badge cloud + switch rows */
.srp-drawer-sub {
    font-size: .65rem;
    color: var(--mix-ink-muted);
    text-transform: none;
    letter-spacing: 0;
}

.srp-badge-cloud {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* Skill tags borrow the tier list's chip, which is sized to sit quietly on a card. Here
   each one is something you tap, so the SRP's copy takes the same 40px target as the
   other filter chips while keeping the category tint. */
.srp-badge-opt {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 12px;
    font-size: .8rem;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    cursor: pointer;
    opacity: .75;
}

.srp-badge-opt:hover,
.srp-badge-opt:focus-visible {
    opacity: 1;
}

.srp-badge-opt-sel {
    opacity: 1;
    outline: 1px solid var(--mix-primary);
}

.srp-card-stepartist {
    color: var(--mix-ink-muted);
}

/* SRP export dialog */
.srp-export {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.srp-export-count {
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.srp-export-columns {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}

.srp-export-grp {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.srp-export-all {
    background: none;
    border: 0;
    padding: 2px 4px;
    font: inherit;
    font-size: .72rem;
    color: var(--mix-primary);
    cursor: pointer;
}

.srp-export-all:hover,
.srp-export-all:focus-visible {
    text-decoration: underline;
}

/* A bundle chip wears the ordinary chip. Its multiplier is what says it is worth many
   columns, and that reads without a second visual language on top. */
.srp-export-mult {
    margin-left: 7px;
    font-size: .74rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.srp-export-unstable {
    color: var(--mix-ink-muted);
    border-top: 1px dashed var(--mix-surface-muted);
    padding-top: 7px;
}

.srp-export-hint {
    color: var(--mix-ink-muted);
}

.srp-export-file {
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    border-top: 1px solid var(--mix-surface-muted);
    padding-top: 8px;
}

/* The shared table shell: the tier lists' table density and the chart SRP's both render
   it, so it lives here rather than in either page. The wrap is what side-scrolls — a
   ten-column table on a phone must move inside its own box, never take the page with it. */
.tier-table-wrap {
    overflow-x: auto;
    max-width: 100%;
}

.tier-table {
    width: 100%;
    border-collapse: collapse;
}

.tier-table th {
    text-align: left;
    color: var(--mud-palette-text-secondary);
    font-size: .75rem;
    padding: 4px 8px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.tier-table td {
    padding: 4px 8px;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* SRP densities: sticker sheet + table. The sheet itself is the tier lists'
   .tier-card-grid.tier-card-grid-compact — the tiles take their width from that grid. */
.srp-table .srp-th-sortable {
    cursor: pointer;
    white-space: nowrap;
}

.srp-table .srp-th-sorted {
    color: var(--mix-ink);
    border-bottom: 2px solid var(--mix-accent);
}

.srp-table-link {
    color: var(--mix-ink);
    font-weight: 600;
}

.srp-table-link:hover {
    color: var(--mix-primary);
}

.srp-table-muted {
    color: var(--mix-ink-muted);
}

.srp-table-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* SRP drawer facets: chip sets, range-slider headers, debut-mix eras */
.srp-facet {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.srp-facet-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: .75rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.srp-facet-value {
    text-transform: none;
    letter-spacing: 0;
    color: var(--mix-ink);
    font-variant-numeric: tabular-nums;
}

.srp-chipset {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.srp-chipset-sub {
    padding-left: 10px;
    border-left: 2px solid var(--mix-surface-muted);
}

/* A filter chip is the drawer's primary control, and a thumb is about 9mm wide: these
   sit at the 40px target rather than the 22px the type alone would give them. The
   drawer is 420px, so a row still fits two or three of the longest names. */
.srp-facet-chip {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    font-size: .85rem;
    border: 1px solid var(--mix-surface-muted);
    border-radius: 999px;
    padding: 0 14px;
    color: var(--mix-ink-muted);
    cursor: pointer;
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: border-color .12s, color .12s, background-color .12s;
}

.srp-facet-chip:hover,
.srp-facet-chip:focus-visible {
    color: var(--mix-ink);
    border-color: var(--mix-primary);
}

/* A plate chip wears its own plate colour, so the row reads as the plate ladder it is rather
   than five identical pills. --plate-chip is set inline from ThemeScales.PlateColor. */
.srp-facet-chip[style*="--plate-chip"] {
    color: color-mix(in srgb, var(--plate-chip) 62%, var(--mix-ink));
    border-color: color-mix(in srgb, var(--plate-chip) 50%, transparent);
}

    .srp-facet-chip[style*="--plate-chip"].srp-facet-chip-on {
        color: var(--mix-primary-contrast);
        background: var(--plate-chip);
        border-color: var(--plate-chip);
    }

.srp-facet-chip-on {
    color: var(--mix-primary-contrast);
    background: var(--mix-primary);
    border-color: var(--mix-primary);
    font-weight: 600;
}

.srp-era {
    margin-top: 6px;
}

.srp-era-name {
    font-size: .68rem;
    color: var(--mix-ink-muted);
    margin-bottom: 3px;
}

/* ── The leaderboard skin ─────────────────────────────────────────────────────
   The Official Leaderboards rankings board is the golden standard for every
   ranked collection on the site, so its vocabulary lives here rather than in
   the section's own <style> block: the Communities boards wear the same look.
   Names keep their olb- prefix — the Official pages and the E2E suite pin them. */

/* Rankings and chart boards render as compact card rows, never tables — a phone
   reads rank, player, and rating with zero side-scrolling (UX rule: tabular
   collections lean compact). */
.olb-rank-card, .olb-board-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    flex-wrap: wrap;
}

.olb-rank-rankbox { min-width: 52px; display: inline-flex; align-items: center; gap: 4px; }

/* Mud chips ship 4px of margin — inside a row that is already budgeting every
   pixel, that reads as a misalignment rather than as spacing. */
.olb-rank-card .mud-chip { margin: 0; }

.olb-board-place { min-width: 40px; font-weight: 700; }

.olb-rank-tail {
    margin-left: auto; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: flex-end; gap: 8px;
}

.olb-rank-expand { padding: 4px 0 10px; }

/* The column variant of the same row. A board carrying several figures per player
   reads as a pile when every figure is flush right, so the figures spread into
   their own columns instead: the owning page supplies the template in
   --olb-grid-cols (and --olb-grid-cols-narrow for the width where its optional
   columns drop out), and the identity column stays pinned left. */
.olb-grid-row, .olb-grid-head {
    display: grid;
    grid-template-columns: var(--olb-grid-cols);
    align-items: center;
    gap: 8px;
    padding: 4px 8px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
}

.olb-grid-row .mud-chip { margin: 0; }

/* Column names, in the table-head voice the sortable boards already use. The header
   is the row template with labels in it, so it drops the same columns at the same
   widths; a label that outruns its column clips rather than reflowing the row. */
.olb-grid-head {
    color: var(--mix-ink-muted);
    font-size: 11.5px;
    letter-spacing: .4px;
    text-transform: uppercase;
    line-height: 1.25;
}

.olb-grid-head span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Figures are read down a column, so they align on their right edge. */
.olb-grid-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 2px;
}

/* Competitive level and PUMBILITY are two ordinary grid columns, never stacked (owner
   call) — the wrapper is display:contents so its two children sit in the template's cells
   directly, at every width. */
.olb-stack { display: contents; }

/* A label that has a short form: the long one until the row runs out of width. */
.olb-short-form { display: none; }

/* Board tags run long (LIKEASLAM01#8073). Lists print the human half — the digits
   identify an account, they don't name anyone — and truncate what's still too long;
   the full tag stays in the row's tooltip and on the player's own page. */
/* The flag is atomic and the name is what gives: a UserLabel truncated as one box
   spends the width on the flag and prints a bare "…", so the label lays out as a
   flex row whose last child — the name — is the only part allowed to shrink.
   min-width:0 is what permits that shrink; without it the text keeps its full
   width and the ellipsis swallows the whole name. */
.olb-player-name {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    vertical-align: middle;
    min-width: 0;
    max-width: 22ch;
    overflow: hidden;
}

.olb-player-name > :not(:last-child) { flex: 0 0 auto; }

.olb-player-name > :last-child {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
}

/* Every UserLabel, everywhere: flag then name, laid out so a bounded caller truncates
   the NAME. max-width keeps the label inside its container instead of overflowing as one
   atomic box — an overflowing atomic box is replaced wholesale by the container's
   ellipsis, which is how a flagged player used to render as a bare "…". */
.user-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    vertical-align: middle;
    min-width: 0;
    max-width: 100%;
}

.user-label > :not(:last-child) { flex: 0 0 auto; }

.user-label > :last-child {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
}

/* Inline-block, not block: this rule reaches every UserLabel on the site, and the
   label sits inline in most of them. It only truncates where a caller has bounded
   the width. */
.user-label-name {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/* A "50× <grade art>" column head: the multiplier and the letter picture read as one
   token, so they never wrap apart. */
.olb-tier-head {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
}

.olb-delta-up { color: var(--mix-primary); font-weight: 700; }

.olb-delta-down { color: var(--mix-accent); font-weight: 700; }

.olb-delta-flat { color: var(--mix-ink-muted); }

/* The leaderboard skin for the collections that need real table semantics
   (sortable columns): same flat surface, hairlines, and row rhythm as the
   rankings cards — the site's one leaderboard look. */
.olb-board-table.mud-table { background: transparent; }

.olb-board-table .mud-table-cell {
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    padding: 4px 8px;
}

.olb-board-table .mud-table-head .mud-table-cell {
    color: var(--mix-ink-muted);
    font-size: 11.5px;
    letter-spacing: .4px;
    text-transform: uppercase;
}

.olb-board-table .mud-table-body .mud-table-row:hover .mud-table-cell {
    background: color-mix(in srgb, var(--mix-ink) 5%, transparent);
}

/* A supplemented row: one whose score came from a linked player's own ledger rather
   than from piugame. Deliberately a rail and a chip, never a background tint — the
   same row can also be YOUR row or a community row, and those own the background.
   Marking it any other way would mean choosing which fact to hide. */
.olb-row-supp {
    border-left: 2px dashed var(--mix-secondary);
    padding-left: 6px;
}

.olb-supp-chip {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 10px;
    letter-spacing: .07em;
    text-transform: uppercase;
    padding: 1px 6px;
    border-radius: 3px;
    white-space: nowrap;
    color: var(--mix-secondary);
    border: 1px solid color-mix(in srgb, var(--mix-secondary) 50%, transparent);
    background: color-mix(in srgb, var(--mix-secondary) 12%, transparent);
}

.olb-board-table tr.olb-row-supp td:first-child {
    border-left: 2px dashed var(--mix-secondary);
}

/* The rail, explained next to the table it marks. The swatch is the same dashed border on
   the same token as .olb-row-supp, so the key cannot drift from the thing it describes. */
.olb-supp-legend {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 0 10px;
    font-size: .8rem;
    color: var(--mix-ink-muted);
}

.olb-supp-legend-rail {
    flex: 0 0 auto;
    width: 0;
    height: 16px;
    border-left: 2px dashed var(--mix-secondary);
}

/* A note the supplemented reading pins above a board it cannot change. */
.olb-reading-note {
    display: flex;
    gap: 9px;
    align-items: flex-start;
    padding: 9px 12px;
    border-radius: 7px;
    margin-bottom: 14px;
    font-size: .875rem;
    line-height: 1.45;
    color: var(--mix-ink);
    background: color-mix(in srgb, var(--mix-secondary) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--mix-secondary) 34%, transparent);
}

.olb-reading-note .mud-icon-root { color: var(--mix-secondary); flex: 0 0 auto; }

/* Row glow: the dashboard vocabulary — you blue, your opt-in crews green. */
.olb-row-me {
    background: color-mix(in srgb, var(--daily-you) 15%, transparent);
    box-shadow: inset 0 0 0 1.5px var(--daily-you);
    border-radius: 6px;
}

.olb-row-community {
    background: color-mix(in srgb, var(--daily-community) 13%, transparent);
    box-shadow: inset 3px 0 0 var(--daily-community), inset -3px 0 0 var(--daily-community);
    border-radius: 6px;
}

/* A board sheds width one column at a time: at 760 the sortable-table variant pins its
   row identifier while the rest side-scrolls and song titles step aside; the community
   grid then drops its play count at 600 and its playstyle chip at 500 (see those blocks
   below); at 500 the compact card rows tighten padding and long labels fall back to their
   short forms. Figures never stack — every value keeps its own column. */
@media (max-width: 760px) {
    .olb-hide-mobile { display: none !important; }

    .olb-song-text { display: none; }

    .olb-player-name { max-width: 16ch; }

    .olb-sticky-first td:first-child, .olb-sticky-first th:first-child {
        position: sticky;
        left: 0;
        z-index: 2;
        background: var(--mix-surface);
        max-width: 200px;
        overflow: hidden;
    }

    .olb-sticky-first td:first-child .mud-typography {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .olb-pager-tight .mud-table-pagination { padding-inline: 2px; }

    .olb-pager-tight .mud-table-pagination-caption { font-size: 11px; margin: 0 4px; }
}

/* The community grid sheds whole columns, never stacking its figures: at 600 the play
   count drops, at 500 the playstyle chip drops (no initials fallback — owner call). The
   header, built from the same template, loses the same columns at the same widths. */
@media (max-width: 600px) {
    .olb-grid-row, .olb-grid-head {
        grid-template-columns: var(--olb-grid-cols-600, var(--olb-grid-cols));
        gap: 6px;
        padding: 3px 4px;
    }

    /* Columns size to their content now, so the header sets smaller to not out-widen a figure. */
    .olb-grid-head { font-size: 10px; letter-spacing: .2px; }

    .olb-hide-narrow { display: none !important; }
}

@media (max-width: 500px) {
    .olb-grid-row, .olb-grid-head {
        grid-template-columns: var(--olb-grid-cols-500, var(--olb-grid-cols-600, var(--olb-grid-cols)));
    }

    .olb-hide-phone { display: none !important; }

    .olb-long-form { display: none; }

    .olb-short-form { display: inline; }

    .olb-rank-card, .olb-board-row { gap: 5px; padding: 3px 4px; }

    .olb-rank-rankbox { min-width: 42px; }

    .olb-rank-card .mud-chip {
        height: 20px;
        padding: 0 7px;
        font-size: 10.5px;
    }

    .olb-rank-card .mud-icon-button { padding: 2px; }

    .olb-first-tail, .olb-hero-listtail, .olb-rank-tail {
        flex-direction: column;
        align-items: flex-end;
        gap: 0;
    }
}

/* ============================================================================
   Life Calculator (/LifeCalculator) — docs/design/life-calculator-redesign.md
   The lifebar is the page's hero instrument: the visible bar (0-1000, the
   rainbow) and the overflow above it, drawn to true proportion.
   ============================================================================ */

.lc-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 18px 24px;
    flex-wrap: wrap;
    padding-bottom: 16px;
}

.lc-sub {
    margin: 7px 0 0;
    max-width: 56ch;
    color: var(--mix-ink-muted);
    font-size: .95rem;
    line-height: 1.5;
}

.lc-eyebrow {
    display: block;
    font-size: .68rem;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    font-weight: 600;
}

.lc-provenance {
    background: none;
    border: 1px solid color-mix(in srgb, var(--mix-accent) 45%, transparent);
    color: var(--mix-accent);
    border-radius: 2px;
    padding: 4px 9px;
    font: 600 .66rem/1.3 var(--font-body);
    letter-spacing: .09em;
    text-transform: uppercase;
    cursor: pointer;
    white-space: nowrap;
}

.lc-provenance-body {
    margin: 10px 0 0;
    padding: 10px 13px;
    border-left: 2px solid var(--mix-accent);
    background: var(--mix-surface);
    font-size: .85rem;
    line-height: 1.55;
    color: var(--mix-ink-muted);
    max-width: 74ch;
}

/* ---------- the bench ---------- */
.lc-bench {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-radius: 3px;
    padding: 18px 20px 20px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 232px;
    gap: 22px 26px;
}

.lc-bench-main {
    min-width: 0;
}

.lc-bench-head {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 12px 18px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}

.lc-level {
    display: flex;
    align-items: center;
    gap: 12px;
}

.lc-level-value {
    font-family: var(--font-display);
    font-size: 1.9rem;
    line-height: 1;
    font-weight: 700;
    min-width: 2.1ch;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.lc-level input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    width: clamp(120px, 20vw, 210px);
    height: 3px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--mix-ink) 18%, transparent);
    cursor: pointer;
}

.lc-level input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--mix-primary);
    border: none;
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--mix-primary) 22%, transparent);
    cursor: pointer;
}

.lc-level input[type="range"]::-moz-range-thumb {
    width: 15px;
    height: 15px;
    border: none;
    border-radius: 50%;
    background: var(--mix-primary);
}

/* ---------- the readout ---------- */
.lc-readout {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

.lc-life {
    font-family: var(--font-display);
    font-size: clamp(2.2rem, 6vw, 3.3rem);
    font-weight: 700;
    line-height: .95;
    font-variant-numeric: tabular-nums;
}

.lc-life-max {
    font-size: .95rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.lc-state {
    margin-left: auto;
    font-family: var(--font-display);
    font-size: .95rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    padding: 2px 9px;
    border-radius: 2px;
}

.lc-state[data-state="overflow-full"] {
    color: var(--life-overflow);
    background: color-mix(in srgb, var(--life-overflow) 15%, transparent);
}

.lc-state[data-state="into-overflow"] {
    color: var(--life-r7);
    background: color-mix(in srgb, var(--life-r7) 15%, transparent);
}

.lc-state[data-state="ok"] {
    color: var(--mix-ink-muted);
    background: color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

.lc-state[data-state="danger"] {
    color: var(--life-danger);
    background: color-mix(in srgb, var(--life-danger) 16%, transparent);
}

.lc-state[data-state="dead"] {
    color: var(--mix-bg);
    background: var(--life-danger);
}

/* ---------- the bar ---------- */
.lc-zones {
    display: flex;
    gap: 2px;
    margin-bottom: 5px;
}

.lc-zone-cap {
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 16%, transparent);
    padding-top: 3px;
}

.lc-zone-cap b {
    color: var(--mix-ink);
    font-variant-numeric: tabular-nums;
}

.lc-zone-cap-overflow {
    border-top-color: color-mix(in srgb, var(--life-overflow) 42%, transparent);
    text-align: right;
}

.lc-track {
    position: relative;
    display: flex;
    gap: 2px;
    height: 52px;
    background: var(--mix-bg);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    padding: 3px;
    border-radius: 2px;
}

.lc-zone {
    position: relative;
    overflow: hidden;
    min-width: 2px;
}

.lc-zone::before {
    content: "";
    position: absolute;
    inset: 0;
    opacity: .1;
}

.lc-zone-visible::before {
    background: var(--life-rainbow);
}

.lc-zone-overflow::before {
    background: var(--life-overflow);
}

/* A multi-note press sweeps rather than snapping. The durations ride custom
   properties the page sets inline, so a x50 press can take longer than a x1 —
   pure CSS, which is what keeps it free on a server circuit. The two zones run in
   SEQUENCE, not together: gaining, the visible bar fills before the overflow starts;
   draining, the overflow empties first. Life crosses the zones in that order. */
.lc-fill {
    position: absolute;
    inset: 0;
}

.lc-fill-visible {
    background: var(--life-rainbow);
    transition: clip-path var(--lc-vis-sweep, .13s) linear var(--lc-vis-delay, 0s);
}

.lc-fill-overflow {
    background:
        repeating-linear-gradient(115deg, transparent 0 5px, color-mix(in srgb, var(--mix-bg) 55%, transparent) 5px 8px),
        linear-gradient(90deg, color-mix(in srgb, var(--life-overflow) 62%, transparent), var(--life-overflow));
    transition: clip-path var(--lc-overflow-sweep, .13s) linear var(--lc-overflow-delay, 0s);
}

.lc-glow {
    position: absolute;
    inset: -1px;
    pointer-events: none;
    border-radius: 2px;
    opacity: 0;
    transition: opacity .35s ease;
    box-shadow: inset 0 0 22px 2px color-mix(in srgb, var(--life-r7) 55%, transparent);
}

.lc-track[data-rainbow="true"] .lc-glow {
    opacity: 1;
}

.lc-track[data-danger="true"] {
    border-color: var(--life-danger);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--life-danger) 45%, transparent);
}

.lc-tick {
    position: absolute;
    top: -3px;
    bottom: -3px;
    width: 1px;
    background: color-mix(in srgb, var(--mix-ink) 55%, transparent);
    pointer-events: none;
}

.lc-tick-danger {
    background: var(--life-danger);
}

.lc-tick span {
    position: absolute;
    top: calc(100% + 3px);
    left: 0;
    transform: translateX(-50%);
    font-size: .6rem;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    white-space: nowrap;
}

.lc-tick-danger span {
    color: var(--life-danger);
}

.lc-scale {
    height: 15px;
}

/* ---------- judgment keys ---------- */
.lc-keys {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 6px;
    margin-top: 22px;
}

.lc-key {
    --lc-k: var(--mix-ink);
    position: relative;
    background: var(--mix-surface-muted);
    border: 1px solid color-mix(in srgb, var(--lc-k) 38%, transparent);
    border-bottom-width: 3px;
    border-bottom-color: var(--lc-k);
    border-radius: 3px;
    padding: 9px 6px 7px;
    cursor: pointer;
    color: var(--mix-ink);
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    transition: transform .07s ease, background .12s ease;
}

.lc-key:hover {
    background: color-mix(in srgb, var(--lc-k) 16%, var(--mix-surface-muted));
}

.lc-key:active {
    transform: translateY(2px);
    border-bottom-width: 1px;
    margin-bottom: 2px;
    background: color-mix(in srgb, var(--lc-k) 30%, var(--mix-surface-muted));
}

.lc-key-delta {
    font-family: var(--font-body);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--lc-k);
    font-variant-numeric: tabular-nums;
}

.lc-key-hint {
    position: absolute;
    top: 3px;
    right: 5px;
    font-family: var(--font-body);
    font-size: .58rem;
    font-weight: 400;
    letter-spacing: 0;
    color: var(--mix-ink-muted);
}

.lc-key-step {
    color: var(--lc-k);
    margin-left: 3px;
}

.lc-key-perfect {
    --lc-k: var(--judg-perfect);
}

.lc-key-great {
    --lc-k: var(--judg-great);
}

.lc-key-good {
    --lc-k: var(--judg-good);
}

.lc-key-bad {
    --lc-k: var(--judg-bad);
}

.lc-key-miss {
    --lc-k: var(--judg-miss);
}

/* ---------- step toggle + run buttons ---------- */
.lc-runs {
    display: flex;
    align-items: center;
    gap: 7px 10px;
    flex-wrap: wrap;
    margin-top: 11px;
}

.lc-runs-label {
    font-size: .63rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    font-weight: 600;
}

.lc-runs-gap {
    flex: 1 1 12px;
}

.lc-seg {
    display: inline-flex;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    border-radius: 3px;
    overflow: hidden;
}

.lc-seg button {
    background: none;
    border: none;
    color: var(--mix-ink-muted);
    font: 600 .74rem/1.3 var(--font-body);
    padding: 5px 12px;
    cursor: pointer;
    font-variant-numeric: tabular-nums;
}

.lc-seg button + button {
    border-left: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
}

.lc-seg button[aria-pressed="true"] {
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
}

.lc-ghost {
    background: none;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 20%, transparent);
    color: var(--mix-ink-muted);
    border-radius: 2px;
    padding: 4px 10px;
    font: 600 .72rem/1.3 var(--font-body);
    cursor: pointer;
}

.lc-ghost:hover {
    color: var(--mix-ink);
    border-color: color-mix(in srgb, var(--mix-ink) 42%, transparent);
}

/* Phoenix 2's electric overflow effect: the note lights up when the state it
   describes is actually on screen. */
.lc-note {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 14px 0 0;
    font-size: .8rem;
    line-height: 1.45;
    color: var(--mix-ink-muted);
    max-width: 62ch;
    transition: color .25s ease;
}

.lc-bolt {
    flex: none;
    font-size: .95rem;
    opacity: .35;
    transition: opacity .25s ease, filter .25s ease;
}

.lc-note[data-live="true"] {
    color: var(--mix-ink);
}

.lc-note[data-live="true"] .lc-bolt {
    opacity: 1;
    filter: drop-shadow(0 0 6px var(--mix-accent));
}

/* ---------- telemetry rail ---------- */
.lc-tele {
    display: flex;
    flex-direction: column;
    gap: 13px;
    border-left: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    padding-left: 20px;
}

.lc-tele-label {
    display: block;
    font-size: .63rem;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    font-weight: 600;
}

.lc-tele-value {
    display: block;
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.lc-tele-miss {
    color: var(--judg-miss);
}

.lc-tele-note {
    display: block;
    font-size: .76rem;
    color: var(--mix-ink-muted);
    margin-top: 1px;
}

.lc-mult-meter {
    position: relative;
    height: 5px;
    margin-top: 6px;
    background: color-mix(in srgb, var(--mix-ink) 12%, transparent);
    border-radius: 3px;
    overflow: hidden;
}

.lc-mult-fill {
    position: absolute;
    inset: 0 auto 0 0;
    background: linear-gradient(90deg, color-mix(in srgb, var(--judg-perfect) 45%, transparent), var(--judg-perfect));
    transition: width var(--lc-sweep, .13s) linear;
}

/* ---------- sections ---------- */
.lc-section {
    margin-top: 34px;
}

.lc-section-head {
    display: flex;
    align-items: baseline;
    gap: 8px 14px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}

.lc-section-sub {
    margin: 0 0 14px;
    color: var(--mix-ink-muted);
    font-size: .9rem;
    line-height: 1.5;
    max-width: 70ch;
}

/* ---------- survival budget ---------- */
.lc-budget {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}

.lc-bud {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-top: 2px solid var(--lc-bud-c, var(--mix-primary));
    border-radius: 3px;
    padding: 12px 13px 13px;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.lc-bud-miss {
    --lc-bud-c: var(--judg-miss);
}

.lc-bud-bad {
    --lc-bud-c: var(--judg-bad);
}

.lc-bud-value {
    font-family: var(--font-display);
    font-size: clamp(2rem, 4vw, 2.7rem);
    font-weight: 700;
    line-height: .95;
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.lc-bud-unit {
    font-family: var(--font-body);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    line-height: 1.2;
}

.lc-bud-what {
    font-size: .86rem;
    line-height: 1.4;
    color: var(--mix-ink);
}

.lc-bud-bar {
    position: relative;
    height: 6px;
    background: var(--mix-bg);
    border-radius: 2px;
    overflow: hidden;
    margin-top: auto;
}

.lc-bud-bar i {
    position: absolute;
    inset: 0 auto 0 0;
    background: var(--life-rainbow);
}

.lc-bud-settle {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.lc-budget-note {
    margin: 11px 0 0;
    font-size: .82rem;
    color: var(--mix-ink-muted);
}

/* ---------- level ladder ---------- */
.lc-ladder {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-radius: 3px;
    padding: 14px 16px 16px;
}

.lc-ladder-head,
.lc-ladder-row {
    display: grid;
    grid-template-columns: 3ch minmax(0, 1fr) 7ch;
    gap: 12px;
}

.lc-ladder-head {
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    padding-bottom: 7px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
}

.lc-ladder-head span:last-child {
    text-align: right;
}

.lc-ladder-row {
    align-items: center;
    padding: 2px 0;
    background: none;
    border: none;
    width: 100%;
    color: inherit;
    font: inherit;
    cursor: pointer;
    text-align: left;
}

.lc-ladder-row:hover {
    background: color-mix(in srgb, var(--mix-ink) 5%, transparent);
}

.lc-ladder-row[data-current="true"] {
    background: color-mix(in srgb, var(--mix-primary) 13%, transparent);
    box-shadow: inset 2px 0 0 var(--mix-primary);
}

.lc-ladder-level {
    font-family: var(--font-display);
    font-size: .95rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--mix-ink-muted);
}

.lc-ladder-row[data-current="true"] .lc-ladder-level {
    color: var(--mix-ink);
}

.lc-ladder-bar {
    display: flex;
    height: 9px;
    gap: 1px;
}

.lc-ladder-visible {
    background: var(--life-rainbow);
    opacity: .95;
}

.lc-ladder-overflow {
    background:
        repeating-linear-gradient(115deg, transparent 0 4px, color-mix(in srgb, var(--mix-surface) 70%, transparent) 4px 6px),
        color-mix(in srgb, var(--life-overflow) 78%, transparent);
}

.lc-ladder-max {
    font-size: .76rem;
    font-variant-numeric: tabular-nums;
    color: var(--mix-ink-muted);
    text-align: right;
}

.lc-ladder-row[data-current="true"] .lc-ladder-max {
    color: var(--mix-ink);
}

.lc-ladder-key {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    margin-top: 12px;
    font-size: .76rem;
    color: var(--mix-ink-muted);
}

.lc-ladder-key i {
    display: inline-block;
    width: 22px;
    height: 8px;
    vertical-align: -1px;
    margin-right: 7px;
}

.lc-ladder-key i.lc-k-visible {
    background: var(--life-rainbow);
}

.lc-ladder-key i.lc-k-overflow {
    background:
        repeating-linear-gradient(115deg, transparent 0 4px, color-mix(in srgb, var(--mix-surface) 70%, transparent) 4px 6px),
        color-mix(in srgb, var(--life-overflow) 78%, transparent);
}

/* ---------- rules of thumb ---------- */
.lc-rules {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.lc-rule {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-radius: 3px;
    padding: 14px 15px 15px;
}

.lc-rule-value {
    font-family: var(--font-display);
    font-size: 2.1rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--lc-rule-c, var(--mix-ink));
}

.lc-rule h3 {
    font-size: 1.08rem;
    letter-spacing: .02em;
    margin: 8px 0 5px;
}

.lc-rule p {
    margin: 0;
    font-size: .87rem;
    line-height: 1.5;
    color: var(--mix-ink-muted);
}

.lc-rule-miss {
    --lc-rule-c: var(--judg-miss);
}

.lc-rule-bad {
    --lc-rule-c: var(--judg-bad);
}

.lc-rule-perfect {
    --lc-rule-c: var(--judg-perfect);
}

.lc-rule-good {
    --lc-rule-c: var(--judg-good);
}

/* ---------- mechanics ---------- */
.lc-mech {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.lc-mech-col {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-radius: 3px;
    padding: 14px 15px 15px;
}

.lc-mech-col h3 {
    font-size: 1.05rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    margin: 0 0 9px;
}

.lc-mech-gain {
    color: var(--judg-perfect);
}

.lc-mech-loss {
    color: var(--judg-miss);
}

.lc-mech-mult {
    color: var(--mix-accent);
}

.lc-mech-col ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.lc-mech-col li {
    font-size: .87rem;
    line-height: 1.5;
    color: var(--mix-ink-muted);
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 10px;
    align-items: baseline;
}

.lc-mech-col li b {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 700;
    color: var(--mix-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.lc-formula {
    margin: 11px 0 0;
    padding-top: 10px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
    font-size: .74rem;
    line-height: 1.5;
    color: var(--mix-ink-muted);
    word-break: break-word;
}

/* ---------- footer ---------- */
.lc-foot {
    margin-top: 36px;
    padding-top: 18px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 20px 30px;
    align-items: start;
}

.lc-quote {
    margin: 0;
    font-family: var(--font-display);
    font-size: 1.5rem;
    line-height: 1.15;
    color: var(--mix-ink);
}

.lc-quote cite {
    display: block;
    margin-top: 5px;
    font-family: var(--font-body);
    font-size: .78rem;
    font-style: normal;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

/* ===== /Titles =====
   Titles are ladders, so the page draws one rail per ladder rather than one row per title
   (docs/design/titles-overhaul.md). Tokens only: this page carries no colour-literal
   allowance and is not to acquire one. */

/* The shell leaves the page flush against the nav, and this one opens on a panel edge or a
   section rule rather than on a heading, so it owes itself the breathing room. */
.title-standing,
.title-anon,
.title-skeleton {
    margin-top: 16px;
}

.title-standing {
    display: grid;
    grid-template-columns: minmax(230px, 1fr) minmax(250px, 1fr);
    gap: 14px 30px;
    align-items: center;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 4px;
    padding: 14px 16px;
    margin-bottom: 20px;
}

.title-eyebrow {
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin: 0 0 6px;
}

.title-worn {
    font-family: var(--font-display);
    font-size: clamp(26px, 6vw, 44px);
    font-weight: 700;
    line-height: 1;
    margin: 0;
    color: var(--mix-ink);
    text-wrap: balance;
}

.title-worn-note {
    color: var(--mix-ink-muted);
    font-size: 13.5px;
    margin: 8px 0 0;
}

.title-tally {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 5px;
}

.title-tally-num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 30px;
    line-height: 1;
    color: var(--mix-ink);
    font-variant-numeric: tabular-nums;
}

.title-tally-of {
    font-size: 13px;
    color: var(--mix-ink-muted);
}

.title-meter {
    height: 10px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--mix-ink) 9%, transparent);
    overflow: hidden;
}

.title-meter i {
    display: block;
    height: 100%;
    background: var(--mix-primary);
    box-shadow: 0 0 8px var(--mix-glow);
}

.title-meter-legend {
    font-size: 12px;
    color: var(--mix-ink-muted);
    margin-top: 6px;
}

.title-anon {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-primary) 40%, transparent);
    border-radius: 4px;
    padding: 12px 16px;
    margin-bottom: 18px;
}

.title-anon p {
    margin: 0;
    flex: 1 1 260px;
    font-size: 14px;
    color: var(--mix-ink);
}

/* Filter furniture sits above the list and never sticks (UX rule 6). */
.title-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding: 9px 0;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    margin-bottom: 18px;
}

.title-search {
    flex: 1 1 190px;
    min-width: 150px;
    margin: 0;
}

.title-chips {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.title-chip {
    font: inherit;
    font-size: 13px;
    background: transparent;
    color: var(--mix-ink-muted);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 20%, transparent);
    border-radius: 999px;
    padding: 2px 12px;
    cursor: pointer;
    transition: color .15s, border-color .15s, background .15s;
}

.title-chip:hover {
    color: var(--mix-ink);
    border-color: color-mix(in srgb, var(--mix-ink) 40%, transparent);
}

.title-chip.on {
    background: color-mix(in srgb, var(--mix-primary) 20%, transparent);
    border-color: var(--mix-primary);
    color: var(--mix-ink);
    font-weight: 600;
}

.title-chip .n {
    opacity: .65;
    margin-left: 5px;
    font-variant-numeric: tabular-nums;
}

.title-section {
    margin: 0 0 26px;
}

.title-section-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding-bottom: 5px;
    margin-bottom: 10px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
}

.title-section-head h2 {
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 600;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--mix-ink);
    margin: 0;
}

.title-section-count {
    font-size: 12.5px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    margin-left: auto;
    white-space: nowrap;
}

.title-rails {
    display: flex;
    flex-direction: column;
}

/* Boss breakers are one short rail per mix, so they tile instead of stacking. */
/* Boss breakers are one short rail per mix. The mix name sits ABOVE its buttons rather than
   beside them: side by side, a long mix name and a 150px button fought over a 190px cell and
   the name lost, truncating to nothing. Stacked, every cell also gets the same button width
   for free — the labels are chart data rather than UI strings, so they are the same two
   near-identical widths in every language, which is what made them look misaligned. */
.title-rails.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 4px 18px;
    align-items: start;
}

.title-rail {
    display: grid;
    grid-template-columns: 168px 1fr auto;
    align-items: center;
    gap: 4px 14px;
    padding: 7px 6px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
}

.title-rails.grid .title-rail {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 6px 6px 10px;
}

.title-rails.grid .title-rail-track {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
}

/* Identical width per cell, so a column of them reads as a column. */
.title-rails.grid .title-pip.wide {
    width: 100%;
    min-width: 0;
    justify-content: center;
}

.title-rail:last-child {
    border-bottom: 0;
}

.title-rail:hover {
    background: color-mix(in srgb, var(--mix-ink) 4%, transparent);
}

.title-rail-name {
    font-family: var(--font-display);
    font-size: 19px;
    font-weight: 600;
    letter-spacing: .04em;
    line-height: 1.1;
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.title-rail-name > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Stacked, the mix name owns the full cell width and no longer needs to truncate. */
.title-rails.grid .title-rail-name > span:first-child {
    overflow: visible;
    white-space: normal;
}

.title-rails.grid .title-rail-name {
    font-size: 14px;
    letter-spacing: .1em;
    color: var(--mix-ink-muted);
}

.title-rail-track {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
}

.title-rail-tail {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 700;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.title-rail-tail b {
    color: var(--mix-ink);
}

.title-rails.grid .title-rail-tail {
    display: none;
}

.title-pip {
    position: relative;
    width: 32px;
    height: 30px;
    flex: 0 0 auto;
    border-radius: 3px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 20%, transparent);
    background: transparent;
    color: var(--mix-ink-muted);
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    overflow: hidden;
    transition: transform .12s ease, border-color .15s, box-shadow .15s;
}

.title-pip:hover {
    transform: translateY(-2px);
    border-color: var(--mix-ink);
    z-index: 2;
}

.title-pip:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
    z-index: 2;
}

.title-pip > span {
    position: relative;
    z-index: 1;
}

.title-pip.wide {
    width: auto;
    min-width: 62px;
    padding: 0 9px;
    font-size: 13px;
    letter-spacing: .06em;
}

.title-pip.earned {
    border-color: color-mix(in srgb, var(--mix-primary) 62%, transparent);
    background: color-mix(in srgb, var(--mix-primary) 17%, transparent);
    color: var(--mix-ink);
}

.title-pip.pg {
    border-color: var(--plate-pg);
    box-shadow: 0 0 8px color-mix(in srgb, var(--plate-pg) 45%, transparent);
}

.title-pip.active {
    border-color: var(--mix-accent);
    color: var(--mix-ink);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--mix-accent) 30%, transparent);
}

/* The fill is this rung's own climb from the rung below it. */
.title-pip.active::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--fill, 0%);
    background: color-mix(in srgb, var(--mix-accent) 30%, transparent);
    z-index: 0;
}

.title-pip.locked {
    border-color: color-mix(in srgb, var(--mix-ink) 15%, transparent);
    color: color-mix(in srgb, var(--mix-ink) 34%, transparent);
}

.title-pip.official {
    border-style: dashed;
}

/* One-offs: titles with no ladder behind them. Name colour is how many players hold it,
   and the glow ramp orders the bands where hue cannot. */
.title-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.title-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 11px 4px 8px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    border-radius: 3px;
    background: color-mix(in srgb, var(--mix-ink) 4%, transparent);
    font: inherit;
    color: var(--mix-ink);
    cursor: pointer;
    transition: transform .12s, border-color .15s;
}

.title-badge:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--mix-ink) 45%, transparent);
}

.title-badge:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

.title-badge.official {
    border-style: dashed;
}

.title-badge-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--band);
}

.title-badge-name {
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 600;
    letter-spacing: .03em;
    color: var(--band);
}

.title-badge.owned {
    border-color: color-mix(in srgb, var(--mix-primary) 55%, transparent);
    background: color-mix(in srgb, var(--mix-primary) 12%, transparent);
}

.title-badge.unowned {
    opacity: .42;
}

.title-badge.unowned .title-badge-name {
    color: var(--mix-ink-muted);
}

.title-empty {
    color: var(--mix-ink-muted);
    padding: 12px 0;
}

/* Loading looks like the layout it becomes (UX rule 9), not a lone spinner. */
.title-skeleton {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: 12px;
}

.title-skeleton-rail {
    height: 44px;
    border-radius: 3px;
    background: color-mix(in srgb, var(--mix-ink) 7%, transparent);
    animation: title-skeleton-pulse 1.4s ease-in-out infinite;
}

@keyframes title-skeleton-pulse {
    0%, 100% {
        opacity: 1;
    }

    50% {
        opacity: .55;
    }
}

/* ---- the detail drawer ---- */
.title-drawer {
    display: flex;
    flex-direction: column;
    height: 100%;
    color: var(--mix-ink);
}

.title-drawer-head {
    position: relative;
    padding: 14px 16px 10px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    flex: 0 0 auto;
}

.title-drawer-eyebrow {
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.lc-foot-src {
    font-size: .84rem;
    line-height: 1.55;
    color: var(--mix-ink-muted);
}

.lc-foot-src a {
    color: var(--mix-primary);
}

/* ---------- narrow widths ---------- */
@media (max-width: 959.98px) {
    .lc-bench {
        grid-template-columns: minmax(0, 1fr);
    }

    .lc-tele {
        border-left: none;
        border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
        padding-left: 0;
        padding-top: 15px;
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
        gap: 14px 18px;
    }

    .lc-budget {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .lc-rules {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .lc-mech {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 639.98px) {
    .lc-track {
        height: 40px;
    }

    .lc-bench {
        padding: 14px 13px 16px;
    }

    .lc-rules {
        grid-template-columns: minmax(0, 1fr);
    }

    .lc-foot {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 479.98px) {
    .lc-keys {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .lc-budget {
        grid-template-columns: minmax(0, 1fr);
    }
}

.title-drawer-head h3 {
    font-family: var(--font-display);
    font-size: 27px;
    font-weight: 700;
    line-height: 1.05;
    margin: 2px 0 4px;
    padding-right: 40px;
}

.title-drawer-close {
    position: absolute;
    top: 8px;
    right: 10px;
}

.title-drawer-body {
    padding: 12px 16px 24px;
    overflow-y: auto;
    flex: 1 1 auto;
}

.title-req {
    font-size: 14px;
    background: color-mix(in srgb, var(--mix-ink) 6%, transparent);
    border-left: 2px solid var(--mix-primary);
    padding: 7px 10px;
    margin: 0 0 14px;
}

.title-note {
    font-size: 12.5px;
    color: var(--mix-ink-muted);
    border: 1px dashed color-mix(in srgb, var(--mix-ink) 26%, transparent);
    border-radius: 3px;
    padding: 7px 9px;
    margin: 0 0 14px;
}

.title-label {
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin: 16px 0 6px;
}

.title-bar {
    position: relative;
    height: 9px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--mix-ink) 10%, transparent);
    overflow: hidden;
}

/* PUMBILITY rung ticks on a one-gem bar (docs/design/pumbility-levels.md §8). The frame wraps
   the bar: 18px of reserved headroom carries the LV.n labels, the overlay aligns to the bar's
   own box, and the ticks overshoot its edges — the bar underneath keeps its rounded clip. The
   current rung's tick and label are the bright ones; hover names the rung in full. */
.pmb-lvl-frame {
    position: relative;
    padding-top: 18px;
}

.pmb-lvl-overlay {
    position: absolute;
    inset: 18px 0 0 0;
    pointer-events: none;
}

.pmb-lvl-tick {
    position: absolute;
    top: -3px;
    bottom: -3px;
    width: 3px;
    margin-left: -1.5px;
    border-radius: 1px;
    background: color-mix(in srgb, var(--mix-ink) 45%, transparent);
    pointer-events: auto;
}

.pmb-lvl-tick b {
    position: absolute;
    bottom: calc(100% + 3px);
    left: 50%;
    transform: translateX(-50%);
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: .03em;
    color: var(--mix-ink-muted);
    white-space: nowrap;
}

.pmb-lvl-tick.cur {
    background: var(--mix-ink);
}

.pmb-lvl-tick.cur b {
    color: var(--mix-ink);
}

.title-bar i {
    display: block;
    height: 100%;
    background: var(--mix-accent);
}

.title-bar.done i {
    background: var(--rarity-emerald);
}

.title-figures {
    display: flex;
    justify-content: space-between;
    font-size: 12.5px;
    color: var(--mix-ink-muted);
    margin-top: 4px;
    font-variant-numeric: tabular-nums;
}

.title-figures b {
    color: var(--mix-ink);
}

.title-hint {
    font-size: 12.5px;
    color: var(--mix-ink-muted);
    margin: 6px 0 0;
}

.title-hint b {
    color: var(--mix-ink);
}

.title-suggest {
    display: flex;
    align-items: center;
    gap: 10px;
    background: color-mix(in srgb, var(--mix-primary) 10%, transparent);
    border-left: 2px solid var(--mix-primary);
    padding: 8px 10px;
}

.title-suggest-folder {
    font-family: var(--font-display);
    font-size: 24px;
    font-weight: 700;
    line-height: 1;
    color: var(--mix-primary);
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
}

.title-suggest-ask {
    font-size: 13px;
    line-height: 1.35;
}

/* One row per reference grade. The rows block is a flex item of .title-suggest, so it has to
   claim the remaining width or its children size to content and the asks stop lining up. */
.title-suggest-rows {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.title-suggest-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

/* The folder column is fixed so every grade's ask starts on the same edge, single-type and
   merged-pool rungs alike. Out-specifies the standalone .title-suggest-folder above. */
.title-suggest-row .title-suggest-folder {
    font-size: 23px;
    min-width: 96px;
}

/* A grade no folder reaches: the number is the ceiling that falls short, not an answer. */
.title-suggest-row.short .title-suggest-folder {
    font-size: 20px;
    color: color-mix(in srgb, var(--mix-ink) 34%, transparent);
}

.title-suggest-row.short .title-suggest-ask {
    color: var(--mix-ink-muted);
}

.title-rarity {
    display: flex;
    align-items: baseline;
    gap: 9px;
}

.title-rarity-pct {
    font-family: var(--font-display);
    font-size: 31px;
    font-weight: 700;
    line-height: 1;
    color: var(--band);
}

.title-holders {
    display: flex;
    flex-direction: column;
}

/* The gem-rung drawer: flat level groups, strongest first (docs/design/pumbility-levels.md §4).
   The group rows stay unmarked on purpose — the viewer's own holder row is the list's only
   highlight, because "Where you stand" above already carries their rung. */
.title-stand {
    display: flex;
    align-items: center;
    gap: 10px;
}

.title-stand-id {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.title-stand-name {
    font-weight: 600;
}

.title-stand-next,
.title-stand-range {
    font-size: 13px;
    color: var(--mix-ink-muted);
}

.title-stand-range {
    white-space: nowrap;
}

.title-lvls {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.title-lvl-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--mix-ink) 5%, transparent);
}

.title-lvl.empty {
    opacity: .45;
}

.title-lvl-name {
    font-weight: 600;
}

.title-lvl-th {
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.title-lvl-n {
    margin-left: auto;
    font-size: 13px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.title-lvl-holders {
    display: flex;
    flex-direction: column;
    margin-left: 8px;
    padding: 2px 0 4px 10px;
    border-left: 2px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
}

.title-lvl-pool {
    margin-left: auto;
    font-size: 13px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 860px) {
    .title-standing {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 700px) {
    .title-standing {
        gap: 10px;
        padding: 11px 12px;
        margin-bottom: 14px;
    }

    .title-worn {
        font-size: clamp(24px, 8vw, 34px);
    }

    .title-controls {
        padding: 7px 0;
        margin-bottom: 12px;
        gap: 6px 8px;
    }

    .title-search {
        flex: 1 1 100%;
    }

    .title-chip {
        padding: 2px 9px;
        font-size: 12.5px;
    }

    .title-section {
        margin-bottom: 20px;
    }

    /* The rail wraps onto its own row; it never side-scrolls. */
    .title-rail {
        grid-template-columns: 1fr auto;
        gap: 3px 10px;
        padding: 9px 4px;
    }

    .title-rail-name {
        grid-column: 1;
    }

    .title-rail-tail {
        grid-column: 2;
    }

    .title-rail-track {
        grid-column: 1 / -1;
        margin-top: 2px;
    }
}

/* Filtered out, not removed: a ladder with holes punched through it stops reading as a
   ladder, so a non-matching rung fades in place. */
.title-pip.dim {
    opacity: .16;
    pointer-events: none;
}

.title-badge.dim {
    opacity: .16;
    pointer-events: none;
}

/* ── Folder levels (docs/design/folder-level-progression.md): a folder is two numbers, and
   these are the two ways it renders. The chip carries the grade in its metal with the glow
   stepping by completion tier; the spectrum lays the whole folder out best-first so length
   reads as completion and hue reads as quality. All colour arrives as tokens — the grade
   metals via --grade-*, everything unplayed via --unplayed-grade. ── */
.fl-chip {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    min-width: 58px;
    padding: 6px 7px 5px;
    border-radius: 9px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    font-family: var(--font-display);
    font-variant-numeric: tabular-nums;
}

.fl-chip-grade {
    font-size: 23px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: .01em;
}

.fl-chip-pct,
.fl-chip-count {
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .07em;
    color: var(--mix-ink-muted);
}

.fl-chip-count {
    font-size: 15px;
    color: var(--unplayed-grade);
}

/* A lamped folder is ringed in its own grade metal — the trophy state, and the one rung
   content growth can take back. */
.fl-lamped {
    border-color: currentColor;
    box-shadow: 0 0 0 1px currentColor, 0 0 16px -4px currentColor;
}

.fl-spectrum {
    width: 100%;
}

.fl-track {
    position: relative;
    height: 18px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--mix-bg) 55%, #000);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
}

.fl-slim .fl-track {
    height: 11px;
    border-radius: 7px;
}

.fl-chunky .fl-track {
    height: 22px;
    border-radius: 11px;
}

.fl-fill {
    position: absolute;
    inset: 1px;
    border-radius: 9px;
}

.fl-slim .fl-fill {
    border-radius: 6px;
}

.fl-chunky .fl-fill {
    border-radius: 10px;
}

/* Ticks are cut out of the bar rather than drawn over it, so they read at every fill colour. */
.fl-tick {
    position: absolute;
    top: -4px;
    bottom: -4px;
    width: 2px;
    border-radius: 1px;
    background: var(--mix-bg);
}


/* The tier list's folder standing: one line and the bar, sitting under the title track. */
.fl-header {
    display: grid;
    gap: 8px;
    margin: 0 0 16px;
    padding: 2px 2px 4px;
}

.fl-header-line {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 700;
    letter-spacing: .02em;
    line-height: 1.1;
}

.fl-header-dot {
    color: var(--mix-ink-muted);
    font-weight: 400;
    margin: 0 4px;
}

/* Folder Levels widget: a 1x1 gives one folder the whole cell, everything wider stacks rows. */
.dash-fl-hero {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-align: center;
}

.dash-fl-hero-grade {
    font-family: var(--font-display);
    font-size: 40px;
    font-weight: 700;
    line-height: 1;
}

.dash-fl-hero-pct {
    font-family: var(--font-display);
    font-size: 13px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.dash-fl-hero-bar {
    width: 100%;
}

.dash-fl-hero-left {
    font-family: var(--font-display);
    font-size: 11px;
    color: var(--mix-ink-muted);
    margin-top: 6px;
    font-variant-numeric: tabular-nums;
}

.dash-fl-rows {
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
    justify-content: center;
}

.dash-fl-row-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 5px;
}

.dash-fl-row-name {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.dash-fl-row-count {
    font-family: var(--font-display);
    font-size: 12px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.dash-fl-row-grade {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
}

.dash-fl-row-pct {
    font-family: var(--font-display);
    font-size: 11px;
    letter-spacing: .05em;
    color: var(--mix-ink-muted);
    margin-left: 6px;
    font-variant-numeric: tabular-nums;
}

/* Vertical spectrum: the community profile stacks folders as columns, so the long axis
   flips and the fill grows from the base. Ticks become horizontal rules. */
.fl-vertical .fl-track {
    height: 100%;
    border-radius: 5px 5px 0 0;
}

.fl-vertical .fl-fill {
    border-radius: 4px 4px 0 0;
}

.fl-vertical .fl-tick {
    top: auto;
    bottom: 0;
    left: -4px;
    right: -4px;
    width: auto;
    height: 2px;
}


/* A lamped folder glows, in its own grade metal — a folder lamped at AA burns copper and one
   lamped at SSS+ burns ice-blue, so the glow says how well it was lamped and not only that it
   was. The hue arrives as currentColor from the component. There is deliberately no
   end-of-track marker: the track own end already IS 100%, so a flag there drew a finish line
   on top of the finish line. */
.fl-track-lamped {
    border-color: currentColor;
    box-shadow: 0 0 12px -2px currentColor;
}

/* Folder Levels config: the running count sits above the grid so a full widget explains
   itself before a tap does nothing. */
.fl-cfg-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-family: var(--font-display);
    font-size: 13px;
    letter-spacing: .04em;
    color: var(--mix-ink-muted);
    margin-bottom: 6px;
}

.fl-cfg-picks {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 10px;
}

/* The Select Folders popover anchor — same shape as the tier list's folder picker. */
.fl-cfg-anchor {
    position: relative;
    display: inline-block;
}

/* A folder grid at its host's cap: unpicked cells go quiet so the grid reads as full,
   while the picked ones stay live because removing is how you make room. */
.folder-picker-level:disabled {
    opacity: .35;
    cursor: not-allowed;
}

/* The 1x1 hero leads with the difficulty ball — nothing else in that cell names the folder. */
.dash-fl-hero > .mud-tooltip-root,
.dash-fl-hero > .difficulty-bubble {
    flex: none;
}

/* ===== Mix Changes — the mix diff =====
   The board wears the rankings-board skin (compact rows, hairline separators, no card per
   row) because that is the site's standard for any dense board. The one encoding this page
   adds is direction: warm means the game calls it harder, cool means easier, taken off the
   existing difficulty ramp so it is never the tier lists' red/green. Every direction colour
   is paired with an arrow and the printed delta. */
.mc {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.mc-head {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.mc-title {
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1;
    letter-spacing: .01em;
}

.mc-sub {
    color: var(--mix-ink-muted);
    max-width: 52ch;
    margin-top: 5px;
}

.mc-mixpair {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.mc-mixsel {
    min-width: 168px;
    max-width: 220px;
}

.mc-tween {
    color: var(--mix-ink-muted);
}

.mc-lookup {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.mc-hint {
    font-size: .82rem;
    color: var(--mix-ink-muted);
}

.mc-notice {
    margin: 0;
}

/* ---- the answer card ---- */
.mc-answer {
    display: flex;
    gap: 13px;
    align-items: flex-start;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-left: 3px solid var(--mix-primary);
    border-radius: 5px;
    padding: 13px 15px;
}

.mc-answer-up {
    border-left-color: var(--diff-hard);
}

.mc-answer-down {
    border-left-color: var(--diff-overrated);
}

.mc-answer-new {
    border-left-color: var(--mix-accent);
}

.mc-answer-gone {
    border-left-color: var(--diff-overrated);
}

.mc-answer-same {
    border-left-color: color-mix(in srgb, var(--mix-ink) 20%, transparent);
}

.mc-answer-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.mc-answer-id {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.mc-answer-song {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.28rem;
    line-height: 1.12;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mc-answer-artist {
    font-size: .79rem;
    color: var(--mix-ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mc-verdict {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.06rem;
    line-height: 1.3;
    margin: 0;
}

.mc-moves {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.mc-move {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 13%, transparent);
    border-radius: 5px;
    padding: 4px 8px;
}

.mc-move-pinned {
    border-color: var(--mix-primary);
    box-shadow: 0 0 0 1px var(--mix-glow);
}

/* The earlier mix's bubble, stated as past tense. */
.mc-was {
    filter: grayscale(.5) brightness(.82);
    display: inline-flex;
}

.mc-arrow {
    color: var(--mix-ink-muted);
    font-size: .85rem;
}

.mc-delta {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .86rem;
    font-variant-numeric: tabular-nums;
    min-width: 30px;
    text-align: right;
}

.mc-up {
    color: var(--diff-hard);
}

.mc-down {
    color: var(--diff-overrated);
}

.mc-quiet {
    font-size: .8rem;
    color: var(--mix-ink-muted);
}

.mc-restepped {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* What did NOT move is part of the answer, so it is always shown rather than hidden
   behind a toggle. */
.mc-unchanged {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.mc-unchanged-label {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: .72rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.mc-unchanged-list {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
    align-items: center;
}

/* Note counts line up as a column across rows, so they get tabular figures. */
.mc-notes {
    font-variant-numeric: tabular-nums;
    font-size: .85rem;
    color: var(--mix-ink-muted);
    white-space: nowrap;
}

.mc-linkish {
    background: none;
    border: 0;
    padding: 0;
    color: var(--mix-secondary);
    cursor: pointer;
    font: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.mc-linkish:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

/* ---- tabs ---- */
.mc-tabs {
    display: flex;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    overflow-x: auto;
}

.mc-tab {
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    padding: 9px 14px 8px;
    color: var(--mix-ink-muted);
    white-space: nowrap;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.02rem;
    letter-spacing: .02em;
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.mc-tab-n {
    font-variant-numeric: tabular-nums;
    font-size: .86rem;
    opacity: .75;
}

.mc-tab[aria-selected="true"] {
    color: var(--mix-ink);
    border-bottom-color: var(--mix-primary);
}

.mc-tab:hover {
    color: var(--mix-ink);
}

.mc-tab:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: -2px;
}

/* ---- the folder picker and what narrows inside it ---- */
.mc-filters {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin: 14px 0;
}

.mc-filters .folder-picker { margin-right: 4px; }

/* The chart-selector suggestion's mix suffix — present only where several mixes feed it. */
.chart-selector-mix { color: var(--mix-ink-muted); font-size: .82em; }

.mc-chip {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 13%, transparent);
    color: var(--mix-ink-muted);
    border-radius: 99px;
    padding: 3px 12px;
    cursor: pointer;
    font-size: .83rem;
}

.mc-chip:hover {
    color: var(--mix-ink);
}

.mc-chip:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

.mc-chip[aria-pressed="true"] {
    background: color-mix(in srgb, var(--mix-primary) 15%, var(--mix-surface));
    border-color: color-mix(in srgb, var(--mix-primary) 55%, transparent);
    color: var(--mix-ink);
}

.mc-filter-sep {
    width: 1px;
    height: 18px;
    background: color-mix(in srgb, var(--mix-ink) 13%, transparent);
}

.mc-groupby {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: .8rem;
    color: var(--mix-ink-muted);
}

.mc-seg {
    display: inline-flex;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 13%, transparent);
    border-radius: 5px;
    overflow: hidden;
}

.mc-seg button {
    background: var(--mix-surface);
    border: 0;
    color: var(--mix-ink-muted);
    cursor: pointer;
    padding: 3px 10px;
    font-size: .81rem;
}

.mc-seg button[aria-pressed="true"] {
    background: color-mix(in srgb, var(--mix-primary) 18%, var(--mix-surface));
    color: var(--mix-ink);
}

.mc-seg button:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: -2px;
}

/* ---- the folder in view, and its rows ---- */
.mc-fgroup {
    display: flex;
    flex-direction: column;
}

/* Names the folder the picker selected. Not a control — the picker is. */
.mc-fhead {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 8px 5px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 22%, transparent);
    position: sticky;
    top: -1px;
    background: var(--mix-surface);
    z-index: 2;
}

.mc-ftitle {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.14rem;
    letter-spacing: .01em;
}

.mc-fcount {
    font-size: .79rem;
    color: var(--mix-ink-muted);
    margin-left: auto;
    font-variant-numeric: tabular-nums;
}

.mc-row {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 4px 6px;
    width: 100%;
    border: 0;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    background: var(--mix-surface);
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.mc-row:hover {
    box-shadow: inset 2px 0 0 var(--mix-primary);
}

.mc-row:hover .mc-name {
    color: var(--mix-primary);
}

.mc-row:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: -2px;
}

.mc-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: .92rem;
}

.mc-tail {
    margin-left: auto;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 7px;
}

/* ---- sticker sheet ---- */
.mc-sheet {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-top: 14px;
}

.mc-stickers {
    display: grid;
    gap: 10px;
    grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
}

.mc-sticker {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-radius: 5px;
    padding: 9px;
    display: flex;
    flex-direction: column;
    gap: 7px;
    text-align: left;
    color: inherit;
    min-width: 0;
}

/* Jacket art is a ~16:9 banner. A fixed height sizes the width from the aspect and
   overflows a fluid card, so the box owns the geometry and the image is bounded to it. */
.mc-sticker-art {
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: 3px;
    overflow: hidden;
    background: var(--mix-surface-muted);
    display: flex;
    align-items: center;
    justify-content: center;
}

.mc-sticker-art img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* The one thing on a sticker worth clicking. */
.mc-ball {
    background: none;
    border: 0;
    padding: 0;
    line-height: 0;
    cursor: pointer;
    border-radius: 3px;
}

.mc-ball:hover {
    filter: brightness(1.25);
}

.mc-ball:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 1px;
}

/* Dimming the card is what says "gone" — desaturating the bubbles instead would cost the
   red-Single / green-Double read for no extra meaning. */
.mc-sticker-gone {
    opacity: .72;
}

.mc-sticker-gone:hover {
    opacity: 1;
}

.mc-sticker-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.02rem;
    line-height: 1.13;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.mc-sticker-artist {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mc-sticker-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
}

.mc-loose {
    display: flex;
    flex-direction: column;
}

.mc-loose-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: .72rem;
    letter-spacing: .15em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin: 8px 0 6px;
}

.mc-empty {
    padding: 26px 14px;
    text-align: center;
    color: var(--mix-ink-muted);
    font-size: .9rem;
    border: 1px dashed color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 5px;
}

@media (min-width: 820px) {
    .mc-head {
        flex-direction: row;
        align-items: flex-end;
        justify-content: space-between;
        gap: 24px;
    }
}

/* Narrow: the grouping control takes its own line instead of squeezing in beside a wrapped
   direction chip. */
@media (max-width: 600px) {
    .mc-groupby {
        margin-left: 0;
        width: 100%;
        justify-content: flex-start;
    }
}

/* ============================================================================
   QUALIFIERS (docs/design/qualifiers-overhaul.md)

   One player page: status, your standing, the board, the pool, how it is scored.
   The board wears the sitewide .olb-rank-card skin; what is new here is the chip,
   which carries one play as a jacket ringed in its grade's metal.
   ============================================================================ */

.qual-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding: 11px 13px;
    border-radius: 10px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.qual-status-id {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.qual-kicker {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .15em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.qual-status h1 {
    margin: 0;
    font-size: 17px;
    line-height: 1.2;
    font-weight: 700;
    letter-spacing: -.012em;
    text-wrap: balance;
}

.qual-clock {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 1px;
    flex: 0 0 auto;
}

.qual-clock-label {
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.qual-clock-value {
    font-variant-numeric: tabular-nums;
    font-size: 17px;
    font-weight: 700;
    line-height: 1.15;
}

/* The urgency thresholds the page already branched on, made visible. */
.qual-clock-far { color: var(--mix-primary); }
.qual-clock-near { color: var(--mix-accent); }
.qual-clock-now { color: var(--mix-secondary); }

/* ---- your standing ---- */
.qual-you {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px;
    padding: 12px 13px;
    border-radius: 10px;
    background: var(--mix-surface);
    box-shadow: inset 0 0 0 1.5px var(--mix-primary), 0 0 22px -8px var(--mix-glow);
}

.qual-you-rank {
    display: flex;
    align-items: baseline;
    gap: 4px;
    flex: 0 0 auto;
}

.qual-you-place {
    font-size: 30px;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.03em;
}

.qual-you-of {
    font-size: 12px;
    font-weight: 700;
    color: var(--mix-ink-muted);
}

.qual-you-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 130px;
}

.qual-you-name {
    font-weight: 700;
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.qual-you-gap { font-size: 12px; color: var(--mix-ink-muted); }
.qual-you-gap b { color: var(--mix-accent); font-variant-numeric: tabular-nums; }

.qual-you-total { text-align: right; flex: 0 0 auto; margin-left: auto; }

.qual-you-total-value {
    font-size: 19px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.015em;
}

.qual-you-total-label {
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.qual-you-empty { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--mix-ink) 16%, transparent); }

/* ---- auto-submit strip ---- */
.qual-link {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    padding: 9px 11px;
    border-radius: 9px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    font-size: 12px;
}

.qual-link-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--mix-ink-muted);
}

.qual-link-on .qual-link-dot {
    background: var(--type-doubles);
    box-shadow: 0 0 7px var(--type-doubles);
}

.qual-link-text { color: var(--mix-ink-muted); flex: 1 1 150px; min-width: 0; }
.qual-link-text b { color: var(--mix-ink); font-weight: 700; }

/* ---- the chip: one play, jacket ringed in its grade ----
   The grade rides as the ring rather than a separate icon, which is what buys
   enough room to show a ten-chart top N in the row. The ladder is deliberately
   not injective (SS+/SS share a metal), so the rating prints underneath and the
   title carries the exact grade and score. */
.qual-chips {
    display: flex;
    align-items: flex-start;
    gap: 5px;
    flex-wrap: nowrap;
}

.qual-chip {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    flex: 0 0 auto;
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.qual-chip-thumb {
    position: relative;
    width: 40px;
    height: 23px;
    border-radius: 3px;
    overflow: hidden;
    display: block;
    box-shadow: 0 0 0 2px var(--qual-grade, var(--unplayed-grade));
    transition: transform .12s ease, box-shadow .12s ease;
}

.qual-chip-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Perfect Game is a plate, not a grade, so it layers a halo over the ring. */
.qual-chip-pg .qual-chip-thumb {
    box-shadow: 0 0 0 2px var(--plate-pg), 0 0 9px 1px color-mix(in srgb, var(--plate-pg) 85%, transparent);
}

.qual-chip-rating {
    font-variant-numeric: tabular-nums;
    font-size: 9.5px;
    line-height: 1.1;
    color: var(--mix-ink-muted);
}

.qual-chip:hover .qual-chip-thumb {
    transform: translateY(-1px);
    box-shadow: 0 0 0 2px var(--qual-grade, var(--unplayed-grade)), 0 3px 9px rgba(0, 0, 0, .55);
}

.qual-chip:focus-visible { outline: none; }
.qual-chip:focus-visible .qual-chip-thumb { outline: 2px solid var(--mix-ink); outline-offset: 2px; }

.qual-chip-more {
    align-self: center;
    font-size: 10.5px;
    font-weight: 700;
    color: var(--mix-ink-muted);
    padding: 5px 6px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

/* ---- the pool ----
   Auto-fill on a minimum track, so a four-chart pool and a thirteen-chart pool
   lay out without a mode switch; the tile floor just drops once it gets big. */
.qual-pool {
    display: grid;
    gap: 9px;
    --qual-card-min: 150px;
    grid-template-columns: repeat(auto-fill, minmax(var(--qual-card-min), 1fr));
}

.qual-pool-many { --qual-card-min: 88px; gap: 7px; }

@media (min-width: 720px) {
    .qual-pool { --qual-card-min: 172px; }
    .qual-pool-many { --qual-card-min: 108px; }
}

.qual-card {
    border-radius: 9px;
    overflow: hidden;
    background: var(--mix-surface);
    display: flex;
    flex-direction: column;
    position: relative;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    appearance: none;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition: transform .13s ease, filter .13s ease;
}

.qual-card:hover { transform: translateY(-2px); filter: brightness(1.09); }
.qual-card:focus-visible { outline: 2px solid var(--mix-ink); outline-offset: 2px; }

.qual-card-jacket {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    display: block;
}

/* Scoped to the art itself, never `.qual-card-jacket img`: the difficulty bubble is a
   MudImage in this box too, and telling it to fill the frame stretched it across the whole
   tile. Same trap as .chart-jacket-art on the chart page. */
.qual-card-art {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.qual-card-jacket::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(7, 11, 21, .05) 40%, rgba(7, 11, 21, .88));
}

/* Same treatment as .chart-jacket-play on the chart page - the jacket is the
   button, and tapping it opens the chart with its video already running. */
.qual-card-play {
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;
    z-index: 3;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding-left: 2px;
    border-radius: 99px;
    pointer-events: none;
    background: rgba(0, 0, 0, .8);
    border: 1px solid rgba(255, 255, 255, .2);
    color: #fff;
    opacity: .85;
    transform: scale(.94);
    transition: opacity .12s, transform .12s, background .12s, border-color .12s;
}

.qual-card-play::before {
    content: "";
    border-style: solid;
    border-width: 6px 0 6px 10px;
    border-color: transparent transparent transparent currentColor;
}

.qual-card:hover .qual-card-play,
.qual-card:focus-visible .qual-card-play { opacity: 1; transform: scale(1); }
.qual-card:hover .qual-card-play { background: rgba(0, 0, 0, .93); border-color: var(--mix-primary); }

.qual-pool-many .qual-card-play { width: 26px; height: 26px; }
.qual-pool-many .qual-card-play::before { border-width: 5px 0 5px 8px; }

.qual-card-bubble { position: absolute; left: 5px; top: 5px; z-index: 2; }

.qual-card-name {
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 4px;
    z-index: 2;
    font-size: 10.5px;
    font-weight: 700;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}

.qual-card-body {
    padding: 7px;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.qual-card-result { display: flex; align-items: center; gap: 6px; }

.qual-card-grade {
    font-weight: 800;
    font-size: 11px;
    letter-spacing: .02em;
    flex: 0 0 auto;
}

.qual-card-score { font-variant-numeric: tabular-nums; font-size: 11.5px; color: var(--mix-ink-muted); }

.qual-card-rating {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 13px;
}

.qual-card-empty { font-size: 11.5px; color: var(--mix-ink-muted); }

.qual-card-state {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    align-self: flex-start;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .09em;
    text-transform: uppercase;
    padding: 2px 6px;
    border-radius: 4px;
}

.qual-card-state-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

/* Four states, each with a ring, a word and a legend entry that agree. */
.qual-card-counting { box-shadow: inset 0 0 0 2px var(--mix-primary), 0 0 20px -10px var(--mix-glow); }

.qual-card-counting .qual-card-state {
    background: color-mix(in srgb, var(--mix-primary) 20%, transparent);
    color: var(--mix-primary);
}

.qual-card-banked { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mix-ink) 28%, transparent); }

.qual-card-banked .qual-card-state {
    background: color-mix(in srgb, var(--mix-ink) 10%, transparent);
    color: var(--mix-ink-muted);
}

/* The suggested state: a gold ring on a chart you have not posted yet. This is the
   nudge the original page computed and, from 2025-06-16, stopped painting. */
.qual-card-suggested { box-shadow: inset 0 0 0 2px var(--mix-accent); }

.qual-card-suggested .qual-card-state {
    background: color-mix(in srgb, var(--mix-accent) 20%, transparent);
    color: var(--mix-accent);
}

.qual-legend-suggested { background: var(--mix-accent); }

.qual-card-untouched {
    border-style: dashed;
    border-color: color-mix(in srgb, var(--mix-ink) 24%, transparent);
    background: transparent;
}

.qual-card-untouched .qual-card-state {
    background: color-mix(in srgb, var(--mix-ink) 7%, transparent);
    color: var(--mix-ink-muted);
}

.qual-card-untouched .qual-card-art { opacity: .5; }

.qual-legend { display: flex; flex-wrap: wrap; gap: 5px 12px; padding-top: 2px; }

.qual-legend span {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 10.5px;
    color: var(--mix-ink-muted);
}

.qual-legend i { width: 9px; height: 9px; border-radius: 3px; flex: 0 0 auto; }
.qual-legend-counting { background: var(--mix-primary); }
.qual-legend-banked { background: color-mix(in srgb, var(--mix-ink) 35%, transparent); }
.qual-legend-untouched { border: 1.5px dashed color-mix(in srgb, var(--mix-ink) 45%, transparent); }

/* ---- entrants with no score, off the ladder ---- */
.qual-unscored {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 8px;
    font-size: 12px;
    color: var(--mix-ink-muted);
    border-top: 1px dashed color-mix(in srgb, var(--mix-ink) 18%, transparent);
}

.qual-unscored b { color: var(--mix-ink); font-weight: 600; }

/* ---- how this is scored ---- */
.qual-rules {
    padding: 11px 13px;
    border-radius: 10px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.qual-rules p { margin: 0; font-size: 12.5px; color: var(--mix-ink-muted); }
.qual-rules p b { color: var(--mix-ink); font-weight: 600; }

.qual-closed {
    padding: 11px 13px;
    border-radius: 10px;
    font-size: 12.5px;
    background: color-mix(in srgb, var(--mix-secondary) 14%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mix-secondary) 45%, transparent);
}

/* ---- submit dialog ---- */
.qual-submit-hero {
    position: relative;
    aspect-ratio: 16 / 7;
    overflow: hidden;
    border-radius: 8px;
    margin-bottom: 10px;
}

/* Same scoping as the pool tile: the hero carries a bubble as well as the art. */
.qual-submit-hero-art { width: 100%; height: 100%; object-fit: cover; display: block; }

.qual-submit-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(7, 11, 21, .15) 30%, rgba(22, 30, 44, .97));
}

.qual-submit-hero-text {
    position: absolute;
    left: 12px;
    right: 12px;
    bottom: 8px;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
}

.qual-submit-hero-text h3 {
    margin: 0;
    font-size: 17px;
    font-weight: 700;
    text-shadow: 0 2px 6px rgba(0, 0, 0, .85);
}

.qual-drop {
    border: 2px dashed color-mix(in srgb, var(--mix-ink) 28%, transparent);
    border-radius: 9px;
    padding: 16px 12px;
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 5px;
    align-items: center;
    transition: border-color .13s, background .13s;
}

.qual-drop:hover {
    border-color: var(--mix-primary);
    background: color-mix(in srgb, var(--mix-primary) 8%, transparent);
}

.qual-drop-title { font-size: 13px; font-weight: 700; }
.qual-drop-hint { font-size: 11px; color: var(--mix-ink-muted); }

.qual-drop-filled {
    border-style: solid;
    border-color: var(--mix-primary);
    padding: 0;
    overflow: hidden;
}

.qual-drop-filled img { width: 100%; display: block; max-height: 150px; object-fit: cover; }

.qual-judge {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 7px;
}

.qual-calc {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 11px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--mix-ink) 6%, transparent);
}

.qual-calc-label {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.qual-calc-value {
    font-size: 19px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}

.qual-calc-tail {
    margin-left: auto;
    text-align: right;
    display: flex;
    flex-direction: column;
    gap: 1px;
    align-items: flex-end;
}

.qual-calc-plate { font-size: 11px; font-weight: 700; }

/* ---- the organiser's own screen ----
   Photos live here and nowhere else: they are reference material for the TO,
   not evidence the field has to audit. There is no approval queue. */
.qual-admin-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.qual-admin-kicker {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: .15em;
    text-transform: uppercase;
    color: var(--mix-accent);
}

.qual-admin-bar h1 {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -.012em;
}

.qual-tallies {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 7px;
}

.qual-tally {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
    border-radius: 8px;
    padding: 8px;
}

.qual-tally-key {
    font-size: 8.5px;
    font-weight: 800;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.qual-tally-value {
    font-size: 17px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}

.qual-tally-flag { color: var(--mix-accent); }

/* duplicates: the pair side by side, keep versus delete */
.qual-dupe {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 10px 11px;
    border-radius: 10px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.qual-dupe p { margin: 0; font-size: 11.5px; color: var(--mix-ink-muted); line-height: 1.45; }
.qual-dupe p b { color: var(--mix-ink); }

.qual-dupe-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 7px 9px;
    border-radius: 7px;
    background: color-mix(in srgb, var(--mix-ink) 6%, transparent);
}

.qual-dupe-keep { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--type-doubles) 60%, transparent); }
.qual-dupe-name { font-weight: 700; font-size: 12.5px; }
.qual-dupe-meta { font-size: 10.5px; color: var(--mix-ink-muted); }

.qual-dupe-total {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 13px;
}

/* entries */
.qual-entry {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 7px 8px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
}

.qual-entry-stale { background: color-mix(in srgb, var(--mix-accent) 8%, transparent); }

.qual-entry-who {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 120px;
}

.qual-entry-name {
    font-weight: 600;
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.qual-entry-sub {
    font-size: 10px;
    color: var(--mix-ink-muted);
    display: flex;
    align-items: center;
    gap: 5px;
    flex-wrap: wrap;
}

.qual-source-chip {
    font-size: 8.5px;
    font-weight: 800;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: 1px 5px;
    border-radius: 3px;
    flex: 0 0 auto;
}

.qual-source-account {
    background: color-mix(in srgb, var(--mix-primary) 20%, transparent);
    color: var(--mix-primary);
}

.qual-source-anon {
    background: color-mix(in srgb, var(--mix-ink) 10%, transparent);
    color: var(--mix-ink-muted);
}

.qual-entry-tail {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

.qual-entry-total { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 13.5px; }

/* per-entry submission review */
.qual-submission {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    padding: 7px 8px;
    border-radius: 8px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

.qual-submission-jacket {
    width: 46px;
    height: 26px;
    border-radius: 4px;
    object-fit: cover;
    flex: 0 0 auto;
    display: block;
}

.qual-submission-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.qual-submission-name {
    font-size: 12px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.qual-submission-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--mix-ink-muted);
}

.qual-submission-tail {
    margin-left: auto;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 7px;
}

/* An imported score has no photo because the official site is the evidence. */
.qual-no-photo {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    padding: 3px 6px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--mix-ink) 7%, transparent);
    text-align: center;
    line-height: 1.25;
    flex: 0 0 auto;
}

.qual-photo {
    max-width: 100%;
    border-radius: 8px;
    display: block;
    margin: 0 auto;
}

.qual-danger {
    padding: 9px 11px;
    border-radius: 8px;
    font-size: 12px;
    line-height: 1.45;
    background: color-mix(in srgb, var(--mix-secondary) 14%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mix-secondary) 42%, transparent);
}

.qual-danger b { font-weight: 700; }

.qual-confirm-list {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin-top: 9px;
}

.qual-confirm-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    padding: 6px 9px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--mix-ink) 6%, transparent);
}

.qual-confirm-item-tail {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    color: var(--mix-ink-muted);
}

.qual-setup-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 7px 0;
    font-size: 12.5px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 9%, transparent);
}

.qual-setup-row:last-child { border-bottom: 0; }
.qual-setup-key { color: var(--mix-ink-muted); }
.qual-setup-value { margin-left: auto; font-weight: 700; text-align: right; }

/* Both qualifier dialogs ask for MaxWidth.False on purpose: MaxWidth.Small would tag them
   `mud-dialog-width-sm`, and charts.css carries a site-wide
   `.mud-dialog-width-sm { max-width: none !important }` that no normal-weight rule can beat.
   With False, MudBlazor never applies that class and these caps govern. */
.mud-dialog.qual-dialog {
    max-width: 520px;
}

.mud-dialog.qual-photo-dialog {
    max-width: 720px;
}

.mud-dialog.qual-photo-dialog .qual-photo {
    max-height: 60vh;
    width: auto;
    object-fit: contain;
}

/* Row breakdown: a chip opens the scores behind the total rather than the chart page. */
.qual-breakdown {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 6px 8px 12px;
}

.qual-breakdown-row {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 8px;
    border-radius: 8px;
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

.qual-breakdown-art {
    width: 46px;
    height: 26px;
    border-radius: 4px;
    object-fit: cover;
    flex: 0 0 auto;
    display: block;
}

.qual-breakdown-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1 1 auto;
}

.qual-breakdown-name {
    font-size: 12.5px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.qual-breakdown-sub { display: flex; align-items: center; gap: 6px; }

.qual-breakdown-rating {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    font-size: 13.5px;
    flex: 0 0 auto;
}

/* Chart picker: the jacket is the identifier here too, and a long song title truncates
   rather than wrapping the row to two lines. */
.qual-pick {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    width: 100%;
}

.qual-pick-art {
    width: 54px;
    height: 30px;
    border-radius: 4px;
    object-fit: cover;
    flex: 0 0 auto;
    display: block;
}

.qual-pick-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===== ChartLeaderboardDialog =====================================================
   The scope rail is the only new furniture here; rows, glows and place colouring are
   LeaderboardDialog's .weekly-lb-* vocabulary so the two boards read as one system. */

.cld-scopes {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    padding-bottom: 10px;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
}

.cld-sub {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    padding: 9px 0;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
}

.cld-chip {
    font-size: .74rem;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, .14);
    background: color-mix(in srgb, var(--mix-ink) 4%, transparent);
    color: var(--mix-ink-muted);
    cursor: pointer;
    white-space: nowrap;
    font-family: inherit;
}

.cld-chip:hover:not(:disabled) {
    color: var(--mix-ink);
}

.cld-chip-on {
    background: color-mix(in srgb, var(--mix-primary) 16%, transparent);
    border-color: color-mix(in srgb, var(--mix-primary) 55%, transparent);
    color: var(--mix-ink);
    font-weight: 600;
}

/* A scope with nothing behind it greys and explains nothing — a disabled control already
   reads as "not here", and a sentence about cohorts costs more than it buys. */
.cld-chip-off {
    opacity: .4;
    cursor: default;
}

.cld-standing {
    display: flex;
    align-items: baseline;
    gap: 9px;
    padding: 10px 0 8px;
}

.cld-standing-place {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.35rem;
    font-variant-numeric: tabular-nums;
}

.cld-standing-scope {
    font-size: .72rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.cld-body {
    max-height: 46vh;
    overflow-y: auto;
}

.cld-empty {
    padding: 18px 4px;
    text-align: center;
    font-size: .85rem;
    color: var(--mix-ink-muted);
}

/* ===== Session breakdown (/Player/{id}/Sessions) ==================================
   The hero's own vocabulary. Score rows are the page's own; the peer boards borrow
   .weekly-lb-* so every ranked list on the site reads the same way. */

.sbd-hero {
    border-radius: 8px;
    overflow: hidden;
}

.sbd-hero-head {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    padding: 14px 18px;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
}

.sbd-hero-who {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.sbd-hero-title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1.1;
}

.sbd-hero-when {
    font-size: .78rem;
    color: var(--mix-ink-muted);
}

.sbd-hero-tag {
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, .14);
}

.sbd-tally {
    margin-left: auto;
    display: flex;
    gap: 18px;
}

.sbd-tally div {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.sbd-tally-v {
    font-family: var(--font-display);
    font-size: 1.4rem;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.sbd-pass {
    color: var(--mud-palette-success);
}

.sbd-up {
    color: var(--mix-primary);
}

.sbd-tally-k {
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.sbd-eyebrow {
    font-family: var(--font-display);
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

/* --- the answer, above the fold --------------------------------------------- */
.sbd-ceremony {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    border-bottom: 1px solid rgba(255, 255, 255, .07);
}

.sbd-pumb {
    padding: 20px 18px 18px;
    border-right: 1px solid rgba(255, 255, 255, .07);
}

.sbd-pumb-lead {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    flex-wrap: wrap;
}

.sbd-pumb-big {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 3.6rem;
    line-height: .86;
    letter-spacing: -.015em;
    font-variant-numeric: tabular-nums;
    color: var(--rarity-prism);
    text-shadow: 0 0 14px var(--mix-glow);
}

.sbd-delta {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--mud-palette-success);
    font-variant-numeric: tabular-nums;
}

.sbd-from {
    margin-top: 8px;
    font-size: .76rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.sbd-rank {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, .07);
    display: flex;
    align-items: baseline;
    gap: 9px;
    flex-wrap: wrap;
}

.sbd-rank-value {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.35rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--rarity-sapphire);
}

.sbd-asof {
    font-size: .68rem;
    color: var(--mix-ink-muted);
}

.sbd-compet {
    padding: 20px 18px 18px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.sbd-compet-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.sbd-compet-label {
    font-size: .76rem;
    color: var(--mix-ink-muted);
    width: 62px;
    flex: none;
}

.sbd-compet-value {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.3rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* --- sections ---------------------------------------------------------------- */
.sbd-section {
    padding: 14px 18px;
    border-bottom: 1px solid rgba(255, 255, 255, .07);
}

.sbd-section:last-child {
    border-bottom: 0;
}

.sbd-section-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.sbd-section-note {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    margin-left: auto;
}

/* --- title bars -------------------------------------------------------------- */
.sbd-tbar {
    margin-bottom: 14px;
}

.sbd-tbar:last-child {
    margin-bottom: 0;
}

.sbd-tbar-meta {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}

.sbd-tbar-scope {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .8rem;
    color: var(--mix-ink-muted);
    min-width: 28px;
}

.sbd-tbar-name {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1rem;
}

.sbd-tbar-pct {
    margin-left: auto;
    font-family: var(--font-display);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.sbd-tbar-was {
    color: var(--mix-ink-muted);
    font-weight: 400;
}

.sbd-tbar-cap {
    margin-top: 5px;
    font-size: .72rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.sbd-track {
    position: relative;
    height: 11px;
    border-radius: 6px;
    background: var(--mix-surface-muted);
    border: 1px solid rgba(255, 255, 255, .07);
    overflow: hidden;
}

.sbd-track-held {
    position: absolute;
    inset: 0 auto 0 0;
    background: color-mix(in srgb, var(--mix-primary) 34%, transparent);
}

/* The travelled segment is the point of the bar, so it is the only part that glows. */
.sbd-track-gain {
    position: absolute;
    top: 0;
    bottom: 0;
    background: linear-gradient(90deg, var(--mix-primary), var(--rarity-prism));
    box-shadow: 0 0 12px var(--mix-glow);
}

/* --- score rows --------------------------------------------------------------- */
.sbd-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 2px;
    border-bottom: 1px solid rgba(255, 255, 255, .05);
}

.sbd-row:last-child {
    border-bottom: 0;
}

.sbd-row-body {
    flex: 1;
    min-width: 0;
}

.sbd-row-line {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.sbd-badge {
    font-size: .74rem;
}

.sbd-peerpct {
    font-size: .68rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

/* "+27,450 over P1". Gold rather than the success green every other gain on this row
   wears: the tail already prints a green delta over your previous Phoenix 2 score, and
   two green numbers measuring different baselines a few pixels apart read as one fact
   repeated. Plain text, not a pill — the pumbility badge is the only outlined thing a
   row gets. */
.sbd-p1 {
    font-size: .72rem;
    color: var(--rarity-gold);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* What this play added to your PUMBILITY pool. The tier list's gain treatment, moved onto a
   row: success green on a green hairline over an 82%-black ground, the same build the
   pumbility page's targets wear so one number means one thing across both pages. The only
   outlined thing in the strip — everything beside it is a bare glyph, which is the point. */
.sbd-gain {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .74rem;
    line-height: 1.25;
    font-variant-numeric: tabular-nums;
    background: rgba(0, 0, 0, .82);
    color: var(--mud-palette-success);
    border: 1px solid var(--mud-palette-success);
    border-radius: 2px;
    padding: 1px 5px;
    white-space: nowrap;
}

/* "23.6 (+0.4)" — the arrow's caption rather than a badge of its own, so it stays quiet
   next to the glyph it explains. */
.sbd-comp {
    font-size: .72rem;
    color: var(--mud-palette-success);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.sbd-row-tail {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
}

.sbd-lbbtn {
    flex: none;
}

/* --- community peers ---------------------------------------------------------- */
.sbd-peerboard {
    margin-bottom: 14px;
}

.sbd-peerboard:last-child {
    margin-bottom: 0;
}

.sbd-peerboard-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 5px;
}

.sbd-peerboard-name {
    font-weight: 600;
    font-size: .86rem;
}

.sbd-peer-club {
    font-size: .68rem;
    color: var(--mix-ink-muted);
    margin-left: 6px;
}

/* Empty states name the action that fills them (UX rule 9). */
.sbd-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 3px;
    padding: 18px;
    border: 1px dashed rgba(255, 255, 255, .14);
    border-radius: 6px;
    font-size: .8rem;
    color: var(--mix-ink-muted);
}

/* --- history table ------------------------------------------------------------ */
.sbd-history {
    margin-top: 8px;
}

.sbd-history-table .sbd-num {
    text-align: right;
}

.sbd-history-current td {
    background: color-mix(in srgb, var(--mix-primary) 8%, transparent);
}

.sbd-mixdot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: middle;
}

.sbd-viewing {
    font-size: .7rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

/* The width ladder stacks the ceremony below the shell's own 960 switch. */
@media (max-width: 959.98px) {
    .sbd-ceremony {
        grid-template-columns: 1fr;
    }

    .sbd-pumb {
        border-right: 0;
        border-bottom: 1px solid rgba(255, 255, 255, .07);
    }

    .sbd-tally {
        width: 100%;
        margin-left: 0;
        justify-content: space-between;
    }
}

/* Height, not aspect: a landscape phone is 844 WIDE and 390 TALL, so the width rule above
   would stack the ceremony exactly when the scarce axis is vertical. A fold unfolded and a
   landscape tablet are both squarish but have height to spare and must not compress. */
@media (max-height: 520px) {
    .sbd-ceremony {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .sbd-pumb {
        border-right: 1px solid rgba(255, 255, 255, .07);
        border-bottom: 0;
        padding: 12px 16px;
    }

    .sbd-pumb-big {
        font-size: 2.4rem;
    }

    .sbd-from {
        display: none;
    }

    .sbd-compet {
        padding: 12px 16px;
        gap: 8px;
    }

    .sbd-tbar-cap {
        display: none;
    }
}

/* ===== Session history cards =======================================================
   Replaces the table. Jackets and counts come from the journal so every session has
   them; the footer only exists where capture ran, which is why the art carries the
   card and the headline is a bonus. */

.sbd-history-filter {
    margin-left: auto;
}

.sbd-datepicker {
    max-width: 170px;
}

/* Four across the 1132px content column at the 268px floor — the page size is two full
   rows, because a page ending mid-row reads as a rendering fault. */
.sbd-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
    gap: 14px;
}

.sbd-card {
    background: var(--mix-surface);
    border: 1px solid rgba(255, 255, 255, .12);
    border-top: 2px solid var(--mix-primary);
    border-radius: 8px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    cursor: pointer;
    transition: border-color .12s, box-shadow .12s;
}

.sbd-card:hover {
    border-color: color-mix(in srgb, var(--mix-primary) 45%, transparent);
}

.sbd-card:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

.sbd-card-now {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--mix-primary) 45%, transparent),
    0 0 22px color-mix(in srgb, var(--mix-primary) 13%, transparent);
}

.sbd-card-head {
    padding: 10px 13px 8px;
}

.sbd-card-when {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.15;
}

.sbd-card-meta {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    margin-top: 1px;
}

.sbd-card-art {
    display: flex;
    gap: 4px;
    padding: 0 13px 10px;
    align-items: center;
}

.sbd-card-more {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    margin-left: 2px;
}

.sbd-card-counts {
    display: flex;
    gap: 14px;
    padding: 0 13px 9px;
    align-items: baseline;
}

.sbd-card-k {
    display: flex;
    flex-direction: column;
}

.sbd-card-v {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.sbd-card-l {
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.sbd-card-span {
    margin-left: auto;
    font-size: .68rem;
    color: var(--mix-ink-muted);
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: .04em;
}

/* Pinned to the bottom so cards of different heights still line their footers up. */
.sbd-card-foot {
    margin-top: auto;
    border-top: 1px solid rgba(255, 255, 255, .06);
    padding: 8px 13px;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-height: 37px;
}

.sbd-card-tag {
    font-size: .75rem;
    white-space: nowrap;
    color: var(--mix-accent);
}

.sbd-card-quiet {
    font-size: .72rem;
    color: var(--mix-ink-muted);
    font-style: italic;
}

.sbd-card-now-tag {
    margin-left: auto;
    font-family: var(--font-display);
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-primary);
}

@media (max-width: 599.98px) {
    .sbd-cards {
        grid-template-columns: 1fr;
    }

    .sbd-history-filter {
        margin-left: 0;
        width: 100%;
    }

    .sbd-datepicker {
        max-width: none;
    }
}

/* A targeted rebuild, not a page load: the content stays put and softens while it swaps.
   Skeletons belong to the first load only. */
.sbd-busy {
    opacity: .55;
    transition: opacity .12s ease-out;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .sbd-busy {
        transition: none;
    }
}

/* ===== Leaderboard row trimmings ===================================================
   Flags come from UserLabel, which owns its own narrow-width behaviour: the flag is
   pinned and only the name shrinks. */

/* Stacking the grade over the plate buys back enough width that the avatar fits at
   every size, so it is no longer the thing that gets dropped. */
.sbd-avatar {
    display: inline-flex;
    align-items: center;
    flex: none;
}

/* The avatar's 24px is the row's height, and everything else here stays under it. These
   read at a glance by colour — the letter itself is confirmation, not the message — so
   they can run well below the type beside them without costing anything. */
.sbd-score-stack {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    line-height: 1.1;
}

.sbd-score-stack > img {
    height: 14px !important;
}

/* margin:0 is load-bearing, not tidiness. Nothing resets <p> — not the UA sheet, not
   MudBlazor, not this file — so the score arrives with a 1em block margin that pushes the
   stack past the row it sits in and leaves the number floating off the icons beside it. */
.sbd-score-stack > p {
    font-size: .82rem;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    margin: 0;
    align-self: center;
}

/* Portrait and square: grade above plate in one column, score beside them. Keyed on aspect
   rather than width because that is the axis that decides whether a row has horizontal room —
   a portrait tablet is wide in pixels and still short of it.

   These rows pass Tooltip="false" to ScoreBreakdown, so the icons and the score are direct
   children here and the grid can simply place them. Two earlier attempts tried to lay out
   through MudTooltip's wrapper instead, and neither worked: display:contents only flattened
   one level, and nth-of-type counts within each element's own parent, so images in separate
   wrappers both read as the first. */
@media (max-aspect-ratio: 1/1), (max-width: 599.98px) {
    /* The two rows are declared rather than left to auto-flow, because the score spans them
       with 1 / -1 and -1 counts back from the end of the EXPLICIT grid. Against implicit
       rows it resolves to line 1, the span collapses to a single row, and the score centres
       on the grade alone instead of on the pair. A broken score has no plate, and the second
       row is then an empty auto track, which is zero tall. */
    .sbd-score-stack {
        display: inline-grid;
        grid-auto-flow: row;
        grid-template-columns: auto auto;
        grid-template-rows: repeat(2, auto);
        align-items: center;
        column-gap: 4px;
        row-gap: 0;
        line-height: 1.05;
    }

    /* Both icons claim column 1; auto-flow drops them into successive rows. Two of them
       at 11px fit inside the avatar's 24px, so stacking costs the row no height over
       sitting side by side. */
    .sbd-score-stack > img {
        grid-column: 1;
        height: 11px !important;
    }

    .sbd-score-stack > p {
        grid-column: 2;
        grid-row: 1 / -1;
        align-self: center;
        margin: 0;
        padding-left: 0 !important;
    }
}

/* The club name is hidden on narrow screens only — a portrait tablet has the width for it,
   and it is width that was truncating it to a letter or two. */
@media (max-width: 599.98px) {
    .sbd-peer-club {
        display: none;
    }
}

.sbd-peer-level {
    font-size: .68rem;
    color: var(--mix-ink-muted);
    margin-left: 6px;
    font-variant-numeric: tabular-nums;
}

/* One line under a rivals board: what the asterisk means, and how much of the roster is missing.
   Silently dropping rivals would make a six-row board look like the whole list. */
.cld-footnote {
    font-size: .68rem;
    color: var(--mix-ink-muted);
    margin: 8px 0 0;
    padding-top: 7px;
    border-top: 1px solid rgba(255, 255, 255, .06);
}

/* ── Rivals (docs/design/rivals.md) ───────────────────────────────────────────────────── */

.rvl-roster {
    display: grid;
    gap: 6px;
}

.rvl-row {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 10px;
    border-radius: 7px;
    background: var(--mix-surface-muted);
    font-size: .85rem;
}

.rvl-row-main {
    flex: 1;
    min-width: 0;
}

.rvl-row-name {
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.rvl-row-meta {
    font-size: .7rem;
    color: var(--mix-ink-muted);
    margin-top: 1px;
}

/* The reverse list carries three buttons on one row; on a phone they wrap into a block rather
   than pushing the row wider than the screen. */
.rvl-row-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 6px;
}

.rvl-tag {
    font-size: .6rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 3px;
    border: 1px solid;
}

.rvl-tag-ghost {
    color: var(--mix-accent);
    border-color: color-mix(in srgb, var(--mix-accent) 45%, transparent);
}

.rvl-tag-crew {
    color: var(--daily-community);
    border-color: color-mix(in srgb, var(--daily-community) 45%, transparent);
}

.rvl-tag-priv, .rvl-tag-gone {
    color: var(--mix-ink-muted);
    border-color: color-mix(in srgb, var(--mix-ink-muted) 40%, transparent);
}

.rvl-code {
    display: flex;
    align-items: center;
    gap: 9px;
    background: var(--mix-background);
    border: 1px solid rgba(255, 255, 255, .14);
    border-radius: 5px;
    padding: 7px 11px;
}

.rvl-code-value {
    font-family: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, monospace;
    font-size: .92rem;
    letter-spacing: .1em;
    flex: 1;
}

.rvl-h2h-top {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 4px 2px 14px;
    flex-wrap: wrap;
}

.rvl-h2h-who {
    display: flex;
    align-items: center;
    gap: 9px;
}

.rvl-h2h-vs {
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--mix-ink-muted);
    letter-spacing: .1em;
}

.rvl-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
    gap: 8px;
}

.rvl-tile {
    background: var(--mix-surface-muted);
    border-radius: 6px;
    padding: 8px 10px;
    text-align: center;
}

.rvl-tile b {
    font-family: var(--font-display);
    font-size: 1.3rem;
    display: block;
    line-height: 1.05;
}

.rvl-tile span {
    font-size: .61rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--mix-ink-muted);
}

/* Ahead is the community green, behind is the rival red — the row-glow vocabulary doing a
   second job rather than a second palette meaning the same thing. */
.rvl-tile-win b, .rvl-ahead {
    color: var(--daily-community);
}

.rvl-tile-lose b, .rvl-behind {
    color: var(--daily-rival);
}

.rvl-muted {
    color: var(--mix-ink-muted);
}

.rvl-cmp-row {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 5px 4px;
    font-size: .8rem;
    border-radius: 5px;
}

.rvl-cmp-row + .rvl-cmp-row {
    border-top: 1px solid rgba(255, 255, 255, .05);
}

/* The chart cell is one hit target and one LINE. nowrap on the flex row is what stops the art
   and the bubble stacking when the column narrows — without it they wrap like words and the row
   grows a second storey. The name truncates instead, with the full title in the tooltip. */
.rvl-cmp-chart {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: nowrap;
    min-width: 0;
    cursor: pointer;
}

.rvl-cmp-chart > :not(.rvl-cmp-song) {
    flex: none;
}

.rvl-cmp-chart:hover .rvl-cmp-song {
    text-decoration: underline;
}

.rvl-cmp-song {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* MudTable ships its OWN overflow-x:auto container, so the scrolling at tablet widths was
   never the wrapper's — it was the table growing past its column and Mud's container obliging.
   Two things fix it, and both are needed.

   First, cap the chart column. A table cell sizes to its content, so a long song name widened
   the whole table instead of truncating inside it; nothing downstream could shrink it back. */
.rvl-cmp-table .mud-table-cell:first-child {
    max-width: 260px;
}

/* Second, the container only scrolls at mobile. Above that the row has room — the name is
   already gone below 760px (.olb-hide-mobile) — so a sideways scrollbar there is a control
   with nothing to do. */
.rvl-cmp-table .mud-table-container {
    overflow-x: visible;
}

@media (max-width: 599.98px) {
    .rvl-cmp-table .mud-table-container {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* The real floor of a mobile row: art, bubble and two score stacks, difference dropped. */
    .rvl-cmp-table .mud-table-container > table {
        min-width: 340px;
    }
}

/* Same breakpoint the score stack uses: at 1:1 and narrower the row has no horizontal room to
   spare, and the difference is the one column whose value is already on screen twice. */
@media (max-aspect-ratio: 1/1), (max-width: 599.98px) {
    .rvl-cmp-diff-col {
        display: none;
    }
}

.rvl-cmp-score {
    font-variant-numeric: tabular-nums;
    min-width: 74px;
    text-align: right;
}

.rvl-cmp-delta {
    min-width: 66px;
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-size: .74rem;
}

.rvl-cmp-score.rvl-ahead, .rvl-cmp-score.rvl-behind, .rvl-cmp-delta.rvl-ahead, .rvl-cmp-delta.rvl-behind {
    font-weight: 600;
}

.rvl-absent {
    padding: 9px 10px;
    border: 1px dashed rgba(255, 255, 255, .14);
    border-radius: 6px;
    font-size: .74rem;
    color: var(--mix-ink-muted);
}

/* ---------------------------------------------------------------------------
   Community Tools: the secret block.
   A key or an invite URL is a thing you copy, not a thing you read, so it wears
   the shape every other developer console uses for one — monospace on a recessed
   ground with the copy control welded to its edge, rather than body text with a
   button somewhere nearby.
   --------------------------------------------------------------------------- */
.ct-secret {
    display: flex;
    align-items: stretch;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 4px;
    background: color-mix(in srgb, var(--mix-bg) 60%, transparent);
    overflow: hidden;
}

.ct-secret pre {
    flex: 1;
    min-width: 0;
    margin: 0;
    padding: 10px 12px;
    font-family: ui-monospace, "Cascadia Mono", Consolas, "Liberation Mono", monospace;
    font-size: .82rem;
    line-height: 1.5;
    /* The value can be a 64-character key on a 360px phone, so it scrolls inside
       its own box rather than pushing the dialog sideways. */
    overflow-x: auto;
    white-space: pre;
}

.ct-secret .ct-secret-copy {
    flex: 0 0 auto;
    border-left: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 0;
    margin: 0;
}

/* Wraps instead of scrolling where the value is a URL a maker reads to tell two
   links apart. */
.ct-secret.ct-secret-wrap pre {
    white-space: pre-wrap;
    word-break: break-all;
    overflow-x: visible;
}

/* ---------------------------------------------------------------------------
   Community Tools: the first-tool wizard.
   Breadcrumbs rather than a step count. Several screens share a crumb — the
   key is created on one and read on the next — and a count would present that
   as more work to endure rather than as one job still in progress.
   --------------------------------------------------------------------------- */
.ct-wiz-crumbs {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    background: color-mix(in srgb, var(--mix-nav) 70%, transparent);
}

.ct-wiz-crumb {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 11px 14px 11px 18px;
    font-size: .82rem;
    font-weight: 600;
    color: var(--mix-ink-muted);
    background: none;
    border: 0;
    cursor: default;
    position: relative;
    font-family: inherit;
}

.ct-wiz-crumb + .ct-wiz-crumb { padding-left: 22px; }

.ct-wiz-crumb + .ct-wiz-crumb::before {
    content: "";
    position: absolute;
    left: 6px;
    top: 50%;
    width: 6px;
    height: 6px;
    margin-top: -3px;
    border-top: 1.5px solid color-mix(in srgb, var(--mix-ink) 20%, transparent);
    border-right: 1.5px solid color-mix(in srgb, var(--mix-ink) 20%, transparent);
    transform: rotate(45deg);
}

.ct-wiz-crumb .ct-wiz-tick {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 1.5px solid color-mix(in srgb, var(--mix-ink) 22%, transparent);
    display: grid;
    place-items: center;
    font-size: .62rem;
    line-height: 1;
}

.ct-wiz-crumb[data-state="done"] { color: var(--mix-ink); cursor: pointer; }
.ct-wiz-crumb[data-state="done"] .ct-wiz-tick { border-color: var(--rarity-emerald); color: var(--rarity-emerald); }
.ct-wiz-crumb[data-state="current"] { color: var(--mix-ink); box-shadow: inset 0 -2px 0 var(--mix-primary); }
.ct-wiz-crumb[data-state="current"] .ct-wiz-tick { border-color: var(--mix-primary); background: var(--mix-primary); }
.ct-wiz-crumb:focus-visible { outline: 2px solid var(--mix-primary); outline-offset: -2px; }

.ct-wiz-optional {
    font-weight: 500;
    opacity: .6;
    font-size: .72rem;
    margin-left: 4px;
}

.ct-wiz-body { padding: 22px 20px 8px; }

/* The controls belong to the step, not to the page around it — inside the
   card's border, on their own ground, right-aligned with the primary last the
   way every dialog in the app already does it. */
.ct-wiz-foot {
    display: flex;
    gap: 10px;
    align-items: center;
    flex-wrap: wrap;
    justify-content: flex-end;
    padding: 14px 20px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    background: color-mix(in srgb, var(--mix-nav) 55%, transparent);
}

.ct-wiz-foot .ct-wiz-note { margin-right: auto; font-size: .76rem; color: var(--mix-ink-muted); }

@media (max-width: 599.98px) {
    .ct-wiz-crumb { padding: 9px 8px 9px 14px; font-size: .74rem; }
    .ct-wiz-crumb + .ct-wiz-crumb { padding-left: 16px; }
    .ct-wiz-optional { display: none; }
}

/* The house rules. Set apart from app chrome because the voice inside is first
   person and singular — these are one person's rules, not the site talking — so
   the left rail is the secondary hue rather than the primary one every other
   panel uses. */
.ct-rules {
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-left: 3px solid var(--mix-secondary);
    border-radius: 4px;
    background: color-mix(in srgb, var(--mix-surface-muted) 60%, transparent);
    padding: 18px 20px;
}

.ct-rules-preamble {
    margin: 0 0 16px;
    border-left: 2px solid color-mix(in srgb, var(--mix-accent) 55%, transparent);
    padding-left: 12px;
    font-style: italic;
    max-width: 60ch;
}

.ct-rules ol {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: ct-rule;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.ct-rules li {
    counter-increment: ct-rule;
    display: grid;
    grid-template-columns: 22px 1fr;
    gap: 10px;
}

.ct-rules li::before {
    content: counter(ct-rule);
    font-size: .74rem;
    font-weight: 700;
    color: var(--mix-secondary);
    font-variant-numeric: tabular-nums;
    padding-top: 3px;
}

.ct-rules li > div > b { display: block; margin-bottom: 2px; }

.ct-rules-foot {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

.ct-rules-agree {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

/* Quieter than the rules above it: registration is the ordinary half of the screen. */
.ct-register {
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 4px;
    padding: 18px 20px;
}

/* The repository check state, beside the field it belongs to. */
.ct-check-state { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ---------------------------------------------------------------------------
   Developer console. The page is a section with routed destinations rather
   than one scroll, so the chrome here is nav plus grouping — the sections
   themselves are ordinary forms and board rows.
   --------------------------------------------------------------------------- */

.ct-console-head {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}

.ct-console-pick {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 1.35rem;
    font-weight: 500;
    color: var(--mix-ink);
    background: none;
    border: 0;
    padding: 0;
    font-family: inherit;
    cursor: pointer;
}

span.ct-console-pick { cursor: default; }

.ct-console-nav {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 12px;
}

/* A group header carries its own escape hatch to the section that owns it. */
.ct-group {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin: 26px 0 10px;
}

.ct-group > :last-child { margin-left: auto; }

.ct-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
    gap: 10px;
}

.ct-stat {
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 4px;
    padding: 12px 14px;
}

.ct-stat .ct-stat-n {
    font-size: 1.55rem;
    font-weight: 500;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.ct-stat .ct-stat-n.ct-stat-sm { font-size: 1.1rem; }

.ct-stat .ct-stat-k {
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: .09em;
    color: var(--mix-ink-muted);
    margin-top: 3px;
}

/* Where every inline "why" paragraph went. Opened by the few who want it. */
.ct-why { margin: 4px 0 14px; max-width: 64ch; }

.ct-why summary {
    cursor: pointer;
    font-size: .78rem;
    color: var(--mix-primary);
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.ct-why summary::-webkit-details-marker { display: none; }

.ct-why summary::before {
    content: "?";
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid currentColor;
    font-size: .62rem;
    display: grid;
    place-items: center;
}

.ct-why[open] summary::before { content: "\00d7"; }

.ct-why p {
    margin: 7px 0 0 19px;
    font-size: .82rem;
    color: var(--mix-ink-muted);
}

/* One delivery mode, or one choice, per line — see the note in ToolWebhookPanel. */
.ct-choices {
    display: flex;
    flex-direction: column;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 4px;
    max-width: 620px;
}

.ct-choice {
    padding: 10px 14px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

.ct-choice:last-child { border-bottom: none; }

.ct-choice .ct-choice-sub {
    display: block;
    font-size: .8rem;
    color: var(--mix-ink-muted);
    margin-left: 32px;
}

/* ---------------------------------------------------------------------------
   Tool directory. Browsing is the job, so rows carry enough to choose from and
   the monogram gives each one something to aim at while scanning.
   --------------------------------------------------------------------------- */

.ct-dir-row {
    display: flex;
    align-items: center;
    gap: 13px;
    flex-wrap: wrap;
    padding: 12px 4px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
}

.ct-dir-row:last-child { border-bottom: none; }

/* Derived from the name — tools have no icon, and a letter is enough to make a
   list of rows scannable without inventing an image field for them. */
.ct-dir-mark {
    width: 38px;
    height: 38px;
    border-radius: 8px;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    font-weight: 700;
    font-size: .9rem;
    color: var(--mix-bg);
}

.ct-dir-who { flex: 1 1 300px; min-width: 0; }

.ct-dir-tail {
    margin-left: auto;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* The page's standing answer to "who can see my stuff", in either direction. */
.ct-dir-strip {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-left: 3px solid var(--mix-primary);
    border-radius: 4px;
    padding: 10px 14px;
    margin-bottom: 22px;
}

.ct-dir-strip.ct-dir-strip-empty { border-left-color: var(--mix-ink-muted); }

.ct-dir-strip > :last-child { margin-left: auto; }

@media (max-width: 599.98px) {
    .ct-dir-mark { display: none; }
    .ct-dir-tail { margin-left: 0; width: 100%; }
}

/* A console section's content. No card, no border — the section nav above it is
   already the boundary, and a paper inside a paper is what made the old console
   read as a stack of equally-loud panels. */
.ct-section { display: block; }

/* ---------------------------------------------------------------------------
   Console cards. One responsibility per card, replacing the horizontal rules
   the sections used to separate concerns — a rule says "something changed"
   without saying what belongs to what, and a page of them reads as one strip.
   --------------------------------------------------------------------------- */

.ct-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 14px;
    align-items: start;
}

/* A card that owns a form wide enough to need the row, or a list. */
.ct-cards > .ct-card-wide { grid-column: 1 / -1; }

.ct-card {
    border: 1px solid color-mix(in srgb, var(--mix-ink) 14%, transparent);
    border-radius: 6px;
    background: color-mix(in srgb, var(--mix-surface) 45%, transparent);
    overflow: hidden;
}

.ct-card-head {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 11px 16px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 8%, transparent);
    background: color-mix(in srgb, var(--mix-nav) 45%, transparent);
}

.ct-card-head .ct-card-action { margin-left: auto; }

.ct-card-body { padding: 16px; }

/* A revealed secret box: shown only after "Set new token", because an empty
   password field beside a value that already exists reads as "it is gone". */
.ct-reveal { max-width: 320px; }

/* ============================================================================
   PUMBILITY page (/Pumbility) — docs/design/pumbility-overhaul.md
   The bar is the organising device: the hero prints it, the curve draws it, the
   board rules it across the pool. Everything is --mix-* so it survives a mix
   switch without a circuit.
   ============================================================================ */

/* The shell leaves the page flush against the nav, and this one opens on an eyebrow rather
   than on a heading, so it owes itself the breathing room. */
.pmb-eyebrow {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    margin: 16px 0 8px;
}

/* The section frame: the number, the pool selector and the bar, above the nav and shared by
   every page in the section. Everything in it starts at the same left edge — the bar card
   used to be pushed right, which reads fine on one line and strands it against the far edge
   with nothing under it the moment the row wraps. */
.pmb-frame {
    display: flex;
    align-items: center;
    gap: 14px 22px;
    flex-wrap: wrap;
    padding-bottom: 14px;
}

.pmb-frame-figure {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* Holds the band's height while the number is still arriving, so the nav under it does not
   jump once it lands. */
.pmb-frame-waiting {
    min-height: 74px;
}

.pmb-frame-nav {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
    padding-top: 12px;
    margin-bottom: 4px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.pmb-curve {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    padding: 14px 16px 16px;
}

.pmb-hero-value {
    font-size: 46px;
    line-height: .96;
}

.pmb-hero-sub {
    font-size: 13px;
    color: var(--mix-ink-muted);
    margin-top: 4px;
}

/* Pool selector — Phoenix 2 only, and it re-ranks the whole section. */
.pmb-poolsplit {
    display: flex;
    gap: 6px;
}

.pmb-poolsplit-seg {
    flex: 0 0 auto;
    min-width: 0;
    border-radius: 4px;
    padding: 6px 8px;
    cursor: pointer;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 12%, transparent);
    background: transparent;
    color: var(--mix-ink-muted);
    font: inherit;
    font-size: 11px;
    text-align: left;
}

.pmb-poolsplit-seg strong {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 17px;
    color: var(--mix-ink);
    font-variant-numeric: tabular-nums;
}

.pmb-poolsplit-seg[aria-pressed="true"] {
    border-color: var(--mix-primary);
    color: var(--mix-ink);
    background: color-mix(in srgb, var(--mix-primary) 12%, transparent);
}

.pmb-poolsplit-seg:focus-visible {
    outline: 2px solid var(--mix-primary);
    outline-offset: 2px;
}

/* The bar callout — the mechanic the section is organised around. */
.pmb-barcard {
    padding: 10px 12px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--mix-accent) 9%, transparent);
    border-left: 3px solid var(--mix-accent);
}

/* Not an empty state: below fifty charts nothing is displaced, so there is no bar
   rather than a missing one. */
.pmb-barcard-none {
    background: color-mix(in srgb, var(--mix-ink) 6%, transparent);
    border-left-color: color-mix(in srgb, var(--mix-ink) 25%, transparent);
}

.pmb-barcard-top {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.pmb-barcard-num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 26px;
    color: var(--mix-accent);
    font-variant-numeric: tabular-nums;
}

.pmb-barcard-label {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.pmb-barcard-who {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    font-size: 12.5px;
    margin-top: 4px;
}

.pmb-barcard-say {
    font-size: 12px;
    color: var(--mix-ink-muted);
    margin-top: 5px;
}

.pmb-dot {
    color: var(--mix-ink-muted);
}

/* --- the pool curve --- */
.pmb-curve {
    display: flex;
    flex-direction: column;
}

.pmb-curve-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.pmb-curve-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
}

.pmb-curve-note {
    font-size: 12px;
    color: var(--mix-ink-muted);
}

/* A DEFINITE height, not min-height. Every bar sizes itself with a percentage height, and a
   percentage resolves against auto as auto — so the whole plot painted empty the moment the
   curve stopped being a grid cell that stretched to a neighbour's height. */
.pmb-curve-plot {
    position: relative;
    height: 190px;
    display: flex;
    align-items: flex-end;
    gap: 2px;
}

.pmb-cbar {
    flex: 1;
    min-width: 0;
    border-radius: 1px 1px 0 0;
    background: var(--chart-doubles);
}

.pmb-cbar.s {
    background: var(--chart-singles);
}

.pmb-cbar.ghost {
    opacity: .3;
}

.pmb-cbar.is-bar {
    outline: 1px solid var(--mix-accent);
}

.pmb-curve-line {
    position: absolute;
    left: 0;
    right: 0;
    border-top: 1px dashed var(--mix-accent);
    pointer-events: none;
}

.pmb-curve-line span {
    position: absolute;
    right: 0;
    top: -18px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-accent);
    background: var(--mix-surface);
    padding: 0 4px;
}

.pmb-curve-axis {
    display: flex;
    justify-content: space-between;
    font-size: 10.5px;
    color: var(--mix-ink-muted);
    margin-top: 5px;
}

.pmb-curve-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 5px 14px;
    font-size: 11.5px;
    color: var(--mix-ink-muted);
    margin-top: 6px;
}

.pmb-legend-ghost {
    opacity: .6;
}

.pmb-swatch {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 2px;
    margin-right: 5px;
    vertical-align: -1px;
}

.pmb-swatch-ghost {
    background: var(--chart-doubles);
    opacity: .3;
}

.pmb-curve-read {
    margin: 10px 0 0;
    padding-top: 10px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    font-size: 13px;
}

/* --- sections --- */
.pmb-block {
    margin-top: 28px;
}

.pmb-block-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}

.pmb-block-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 22px;
    margin: 0;
}

.pmb-block-lede {
    font-size: 13.5px;
    color: var(--mix-ink-muted);
    max-width: 62ch;
    margin: 2px 0 14px;
}

/* The Phoenix 2 peer line under the targets' lede: one chip per chart type in the selected pool —
   the peer count, or "N/50 charts" for a type whose pool is not yet full — with the definition in
   the chip's tooltip. A count, not a sentence (docs/design/pumbility-overhaul.md §3.3). */
.pmb-peer-line {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: -6px 0 12px;
}

.pmb-peer-chip {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    color: var(--mix-ink);
    cursor: help;
}

.pmb-peer-chip[data-lit="false"] {
    color: var(--mix-ink-muted);
    font-weight: 500;
    border-style: dashed;
}


/* --- targets, comfortable --- */
/* One treatment for both jacket badges: the mix accent on the mix accent, over the black
   backdrop. The number says how MUCH and nothing else, the grade says what you would come
   away with — which KIND of row it is rides the card's border (owner, 2026-08-06).
   Deliberately the mix accent rather than the pass green: the border language owns green,
   and MixPalette.Success is one constant across every mix, so a badge painted with it says
   nothing about where you are. Declared AFTER .tier-chart-card-corner so it wins that rule's
   border shorthand on source order, the same contract the card border language runs on. */
.pmb-corner-gain {
    border-color: var(--mix-primary);
    color: var(--mix-primary);
}

.pmb-legend {
    margin-top: 0;
}

.pmb-tcard-meta {
    font-size: 11.5px;
    color: var(--mix-ink-muted);
    margin-top: 3px;
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.pmb-tcard-why {
    font-size: 11px;
    margin-top: 3px;
}

.pmb-arrow {
    color: var(--mix-ink-muted);
    font-size: 11px;
}

.pmb-none {
    color: var(--mix-ink-muted);
}

.pmb-num {
    font-variant-numeric: tabular-nums;
}

.pmb-muted {
    color: var(--mix-ink-muted);
}

.pmb-empty {
    color: var(--mix-ink-muted);
    font-size: 13.5px;
}

/* --- targets, table --- */
.pmb-table td {
    white-space: nowrap;
}

.pmb-table .pmb-r {
    text-align: right;
}

.pmb-row {
    cursor: pointer;
}

.pmb-ident {
    white-space: normal;
}

.pmb-ident-cell {
    display: flex;
    align-items: center;
    gap: 8px;
}

.pmb-ident-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 30ch;
}

.pmb-gain-cell {
    color: var(--mix-primary);
    font-variant-numeric: tabular-nums;
}

/* The Peers IQR: the peers' first and third quartiles as two grades with a dash between them
   (docs/design/pumbility-overhaul.md D30). One dash on every row — the grades say the width. */
.pmb-iqr {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    cursor: help;
}

.pmb-iqr-conn {
    color: var(--mix-ink-muted);
    font-size: 12px;
    line-height: 1;
}

.pmb-iqr-label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

/* --- the pool board --- */
.pmb-board {
    display: flex;
    flex-direction: column;
}

.pmb-rankrow {
    cursor: pointer;
    gap: 10px;
}

.pmb-place {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    color: var(--mix-ink-muted);
    width: 26px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.pmb-rankrow .pmb-ident {
    min-width: 0;
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
}

.pmb-rname {
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pmb-tail {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.pmb-val {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
    font-variant-numeric: tabular-nums;
}

.pmb-at-bar {
    background: color-mix(in srgb, var(--mix-accent) 10%, transparent);
}

.pmb-below {
    opacity: .55;
}

.pmb-barrule {
    display: flex;
    align-items: center;
    margin: 2px 0;
    padding: 3px 8px;
    border-top: 1px dashed var(--mix-accent);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 10.5px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-accent);
}

/* --- Phoenix 2 carryover --- */
.pmb-flip {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    padding: 15px 16px;
}

.pmb-flip-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px 22px;
}

.pmb-flip-col-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 7px;
}

.pmb-flip-col-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.pmb-flip-col-name.pmb-p1 {
    color: var(--mix-ink-muted);
}

.pmb-flip-col-name.pmb-p2 {
    color: var(--mix-primary);
}

.pmb-flip-total {
    font-size: 12px;
    color: var(--mix-primary);
}

.pmb-flip-bar {
    display: flex;
    height: 30px;
    border-radius: 3px;
    overflow: hidden;
}

.pmb-flip-seg {
    display: grid;
    place-items: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    color: var(--mix-ink);
}

.pmb-flip-seg.s {
    background: var(--chart-singles);
}

.pmb-flip-seg.d {
    background: var(--chart-doubles);
}

.pmb-flip-say {
    margin-top: 14px;
    font-size: 14px;
    line-height: 1.55;
}

.pmb-factrow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px;
    margin-top: 14px;
}

.pmb-fact {
    background: var(--mix-surface-muted);
    border-radius: 4px;
    padding: 9px 11px;
}

.pmb-fact-num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 24px;
    font-variant-numeric: tabular-nums;
    line-height: 1.05;
}

.pmb-fact-of {
    font-size: 15px;
}

.pmb-fact-lbl {
    font-size: 11.5px;
    color: var(--mix-ink-muted);
    margin-top: 2px;
}

/* Where a repriced record would land on each ladder. Never a title held — the label says
   "would", and every chip carries the pool value that put it there (section 8.2). */
.pmb-lands {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.pmb-lands-lbl {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.pmb-lands-row {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.pmb-chip {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 6px 11px;
    border-radius: 4px;
    background: var(--mix-surface-muted);
    border: 1px solid color-mix(in srgb, var(--mix-primary) 35%, transparent);
    min-width: 0;
}

.pmb-chip-t {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: .05em;
    color: var(--mix-primary);
    white-space: nowrap;
}

.pmb-chip-m {
    font-size: 11px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* --- the projection spread: a folder laid out on what your level scores there --- */
/* Lives here rather than in a Razor <style> block, which is page-scoped — a shared component
   styled that way renders unstyled on every other page that picks it up. */
.spread-scroll {
    overflow-x: auto;
}

/* No value column: the numbers live on the markers, which buys the track most of the width
   back — the thing the spread is actually made of. */
.spread {
    /* The region overlay derives its inset from the same two numbers as the grid below, because
       pixel-guessing the alignment is exactly what breaks when a column width changes. */
    --spread-namecol: 190px;
    --spread-gap: 14px;
    min-width: 460px;
    position: relative;
    display: flex;
    flex-direction: column;
    padding-top: 26px;
}

.spread-row {
    position: relative;
    display: grid;
    grid-template-columns: var(--spread-namecol) 1fr;
    align-items: center;
    gap: var(--spread-gap);
    height: 34px;
    border-radius: 4px;
}

/* The row highlight is the alignment aid — it is what lets an eye carry a dot back to the title
   it belongs to. A vertical rule through the dot as well was one guide too many. */
.spread-row:hover {
    background: color-mix(in srgb, var(--mix-ink) 7%, transparent);
}

.spread-row:hover .spread-title {
    color: var(--mix-ink);
}

.spread-regions {
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(var(--spread-namecol) + var(--spread-gap));
    right: 0;
    pointer-events: none;
}

.spread-region {
    position: absolute;
    top: 0;
    bottom: 0;
}

.spread-region i {
    position: absolute;
    inset: 0;
    opacity: .13;
}

/* Vertical at every width. Rotated, a band label needs about 12px rather than the 90 its
   horizontal form wanted, so it survives a narrow band and a phone alike — which is what lets
   the row drop the tier name entirely instead of printing it beside every number. */
.spread-region b {
    position: absolute;
    top: 3px;
    left: 2px;
    font-size: 9px;
    letter-spacing: .08em;
    text-transform: uppercase;
    font-weight: 700;
    white-space: nowrap;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    max-height: calc(100% - 6px);
    overflow: hidden;
}

.spread-edge {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: color-mix(in srgb, var(--mix-ink) 22%, transparent);
}

.spread-name {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: 12.5px;
    color: var(--mix-ink-muted);
    cursor: pointer;
}

.spread-name:hover .spread-title, .spread-name:focus-visible .spread-title {
    color: var(--mix-primary);
    text-decoration: underline;
}

.spread-jacket {
    width: 24px;
    height: 24px;
    border-radius: 3px;
    flex: none;
    background-size: cover;
    background-position: center;
}

/* A long title ellipses rather than widening the column and dragging the track with it. */
.spread-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.spread-title.spread-unplayed {
    font-style: italic;
}

.spread-track {
    position: relative;
    height: 100%;
}

/* The marker is the hit area and the tooltip's anchor. It is OUR element with the tooltip
   inside it, never MudTooltip's own root: that root carries .mud-tooltip-root{width:auto} and
   .mud-tooltip-inline{display:inline-block} at the same specificity as anything added
   alongside, so a marker class landing there loses its width and its display and collapses.
   22px because a fingertip cannot reliably hit an 11px dot, and the readout is now the only
   place the number lives. */
.spread-marker {
    position: absolute;
    top: 50%;
    width: 22px;
    height: 22px;
    margin: -11px 0 0 -11px;
}

.spread-marker .mud-tooltip-root {
    position: absolute;
    inset: 0;
}

/* Centred on margins rather than a transform, so the diamond below can spend its transform on
   the rotation without having to restate the centring. */
.spread-shape {
    display: block;
    position: absolute;
    left: 50%;
    top: 50%;
    width: 11px;
    height: 11px;
    margin: -5.5px 0 0 -5.5px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--mix-bg);
}

/* Unplayed loses its fill and nothing else — the projection is just as real there. */
.spread-shape.spread-unplayed {
    background: var(--mix-bg) !important;
    border: 2px solid;
    box-shadow: none;
}

.spread-mine .spread-shape {
    width: 9px;
    height: 9px;
    margin: -4.5px 0 0 -4.5px;
    border-radius: 0;
    transform: rotate(45deg);
    border: 1.5px solid var(--mix-ink);
    background: var(--mix-bg);
    box-shadow: none;
}

/* Clamped to the edge and drawn as an arrow: the row still says "off the bottom" rather than
   claiming the score sits at the axis floor. The border box is 13x10, so the centring margins
   are its own halves rather than the circle's. */
.spread-off .spread-shape {
    width: 0;
    height: 0;
    border: 5px solid transparent;
    margin: -5px 0 0 -6.5px;
    background: none;
    transform: none;
    box-shadow: none;
    border-radius: 0;
}

/* currentColor, so the arrow keeps whatever the marker was going to be: the band's colour for
   a projection, the behind/ahead ramp for the player's own score. */
.spread-off-left .spread-shape {
    border-right: 8px solid currentColor;
}

.spread-off-right .spread-shape {
    border-left: 8px solid currentColor;
}

/* Catches the click that dismisses a pinned readout, and nothing else: no background, no
   scroll lock, below the popover's 1200 and above the page. */
.spread-clickaway {
    position: fixed;
    inset: 0;
    z-index: 1198;
}

/* While a readout is pinned the spread rises above the click-away layer, so tapping a SECOND
   marker reaches that marker and moves the readout. Without it the layer is the hit target for
   the whole viewport and moving a readout took two taps: one to dismiss, one to open. Below
   MudPopover's 1200 so the readout itself still draws on top. */
.spread-pinned {
    z-index: 1199;
}

/* The popover's own box: MudPopover brings no padding of its own. */
.spread-pop {
    padding: 7px 10px;
}

/* The grade rail: the first marker to reach each letter carries its badge, giving the track a
   scale down its side without the value column coming back. Click-through, so it cannot steal
   the marker's hit area, and flipped inside near the right edge so it never hangs off. */
.spread-rail {
    position: absolute;
    top: 50%;
    left: calc(100% + 1px);
    transform: translateY(-50%);
    pointer-events: none;
    opacity: .92;
    line-height: 0;
}

.spread-rail-left {
    left: auto;
    right: calc(100% + 1px);
}

.spread-readout {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* The song, so a pinned readout says which row it belongs to. Below 700px the row is a jacket
   and a track, so without this a number on screen names nothing. Ellipsed rather than wrapped:
   a two-line title pushes the figures off a phone. */
.spread-pop-title {
    font-size: 11px;
    font-weight: 600;
    color: var(--mix-ink-muted);
    max-width: 24ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.spread-figures {
    display: flex;
    align-items: center;
    gap: 6px;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
}

.spread-offnote {
    font-weight: 400;
    opacity: .75;
}

/* Below this the title gives way to the jacket alone and the track takes the width. The band
   labels stay: vertical, they fit here as well as anywhere, and they are what keeps the dot's
   colour from being the only channel carrying the tier. */
@media (max-width: 700px) {
    .spread {
        --spread-namecol: 30px;
        --spread-gap: 8px;
        min-width: 0;
        padding-top: 0;
    }

    .spread-row {
        height: 38px;
        border-radius: 0;
        border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 7%, transparent);
    }

    .spread-title {
        display: none;
    }
}

/* --- the patience card: sitewide, for waits a page cannot shorten --- */
/* Lives here rather than in a Razor <style> block, which is page-scoped — a shared component
   styled that way renders unstyled on every other page that uses it. */
/* Full width of whatever it is dropped into, with its contents centred: it stands in for a
   whole region rather than sitting beside one, so anything less than the full width reads as
   a second thing still loading next to the thing that is telling you so. */
.patience-card {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    padding: 28px 16px 30px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 14px;
}

/* Five panels stepping in sequence. Motion without a spinner, and the one thing on the page
   that could only belong to this game. */
.patience-pad {
    /* One step of the chart. Every pattern below counts its cycle in these. */
    --patience-beat: .32s;
    display: grid;
    grid-template-columns: repeat(3, 20px);
    grid-template-rows: repeat(3, 20px);
    gap: 4px;
}

.patience-panel {
    display: block;
    border-radius: 3px;
    background: color-mix(in srgb, var(--mix-ink) 13%, transparent);
    animation-timing-function: steps(1, end);
    animation-iteration-count: infinite;
}

.patience-ul { grid-area: 1 / 1; }
.patience-ur { grid-area: 1 / 3; }
.patience-ct { grid-area: 2 / 2; }
.patience-dl { grid-area: 3 / 1; }
.patience-dr { grid-area: 3 / 3; }

/* Real step patterns, one per CYCLE (owner, 2026-08-08). Each begins AND ends on the
   bottom-left arrow, so whichever comes next picks up mid-stride — which is what lets
   js/patience.js swap the pattern at the cycle boundary with no visible seam. The server picks
   the first one, so a pad still steps a real chart when the script never arrives.

   A panel that lights ONCE gets the shared flash keyframe plus a delay. A panel that lights
   more than once gets a keyframe of its own, spelling out every beat.

   ⚠ It cannot instead declare the shared keyframe twice with two delays, which is the obvious
   economy and is wrong: two animations on one element do not merge, they compete, and for any
   property both of them touch the LAST one in the list wins outright. Since these keyframes
   span the whole cycle, the second instance overrode the first at every moment and only its
   delay was ever visible — M run collapsed to a right-to-left sweep and Spin's centre lit once
   instead of four times.

   The flash lasts exactly one beat, so its width is a fraction of the cycle — hence one shared
   keyframe per cycle length rather than one overall. */
@keyframes patience-flash-8 {
    0% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    11.25% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    12.5%, 100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

@keyframes patience-flash-6 {
    0% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    15% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    16.667%, 100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

/* Keyframes for the panels that light more than once. Beat i of an eight-step cycle runs from
   i × 12.5%, and of a six-step cycle from i × 16.667%; the panel is lit for the first nine
   tenths of its beat and dark the rest of the cycle. */
@keyframes patience-mrun-ul { /* beats 1 and 7 */
    0%, 12.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    12.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    23.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    25%, 87.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    87.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    98.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

@keyframes patience-mrun-ct { /* beats 2 and 6 */
    0%, 24.99% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    25% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    36.25% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    37.5%, 74.99% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    75% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    86.25% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    87.5%, 100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

@keyframes patience-mrun-ur { /* beats 3 and 5 */
    0%, 37.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    37.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    48.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    50%, 62.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    62.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    73.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    75%, 100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

@keyframes patience-spin-ct { /* beats 1, 3, 5 and 7 — the centre carries this whole pattern */
    0%, 12.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    12.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    23.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    25%, 37.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    37.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    48.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    50%, 62.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    62.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    73.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    75%, 87.49% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    87.5% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    98.75% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

@keyframes patience-six-ct { /* beats 1 and 4 of six — shared by the standard run and cross overs */
    0%, 16.66% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    16.667% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    31.667% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    33.333%, 66.66% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
    66.667% { background: var(--mix-primary); box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent); }
    81.667% { background: color-mix(in srgb, var(--mix-primary) 45%, transparent); box-shadow: 0 0 0 transparent; }
    83.333%, 100% { background: color-mix(in srgb, var(--mix-ink) 13%, transparent); box-shadow: 0 0 0 transparent; }
}

/* M run — up the left, through the middle, down the right, and back the way it came.
   BL · TL · C · TR · BR · TR · C · TL */
.patience-mrun .patience-panel { animation-name: patience-flash-8; animation-duration: calc(var(--patience-beat) * 8); }
.patience-mrun .patience-dl { animation-delay: 0s; }
.patience-mrun .patience-ul { animation-name: patience-mrun-ul; }
.patience-mrun .patience-ct { animation-name: patience-mrun-ct; }
.patience-mrun .patience-ur { animation-name: patience-mrun-ur; }
.patience-mrun .patience-dr { animation-delay: calc(var(--patience-beat) * 4); }

/* Spin — back to the centre between every corner.
   BL · C · TL · C · TR · C · BR · C */
.patience-spin .patience-panel { animation-name: patience-flash-8; animation-duration: calc(var(--patience-beat) * 8); }
.patience-spin .patience-dl { animation-delay: 0s; }
.patience-spin .patience-ct { animation-name: patience-spin-ct; }
.patience-spin .patience-ul { animation-delay: calc(var(--patience-beat) * 2); }
.patience-spin .patience-ur { animation-delay: calc(var(--patience-beat) * 4); }
.patience-spin .patience-dr { animation-delay: calc(var(--patience-beat) * 6); }

/* Standard run — the ordinary way round.
   BL · C · TL · TR · C · BR */
.patience-run .patience-panel { animation-name: patience-flash-6; animation-duration: calc(var(--patience-beat) * 6); }
.patience-run .patience-dl { animation-delay: 0s; }
.patience-run .patience-ct { animation-name: patience-six-ct; }
.patience-run .patience-ul { animation-delay: calc(var(--patience-beat) * 2); }
.patience-run .patience-ur { animation-delay: calc(var(--patience-beat) * 3); }
.patience-run .patience-dr { animation-delay: calc(var(--patience-beat) * 5); }

/* Cross overs — every step lands on the far side.
   BL · C · TR · BR · C · TL */
.patience-cross .patience-panel { animation-name: patience-flash-6; animation-duration: calc(var(--patience-beat) * 6); }
.patience-cross .patience-dl { animation-delay: 0s; }
.patience-cross .patience-ct { animation-name: patience-six-ct; }
.patience-cross .patience-ur { animation-delay: calc(var(--patience-beat) * 2); }
.patience-cross .patience-dr { animation-delay: calc(var(--patience-beat) * 3); }
.patience-cross .patience-ul { animation-delay: calc(var(--patience-beat) * 5); }

.patience-line {
    font-family: var(--font-display);
    font-size: 21px;
    font-weight: 600;
    letter-spacing: .01em;
    line-height: 1.15;
    color: var(--mix-ink);
    margin: 0;
}

.patience-sub {
    font-size: 13px;
    line-height: 1.5;
    color: var(--mix-ink-muted);
    margin: 0;
    max-width: 34ch;
}

/* Two classes deliberately, not one: the step patterns above select as `.patience-mrun
   .patience-ul`, and a bare `.patience-panel` here would lose to them on specificity and leave
   the pad animating for someone who asked it not to. Matching their weight and sitting later in
   the file is what makes this win. */
@media (prefers-reduced-motion: reduce) {
    .patience-pad .patience-panel {
        animation: none;
    }

    .patience-pad .patience-ct {
        background: var(--mix-primary);
        box-shadow: 0 0 10px color-mix(in srgb, var(--mix-primary) 55%, transparent);
    }
}

/* --- loading, rule 9: shaped like what it becomes --- */
.pmb-skeleton {
    background: color-mix(in srgb, var(--mix-ink) 8%, transparent);
    border-radius: 6px;
    animation: pmb-pulse 1.4s ease-in-out infinite;
}

.pmb-skeleton-targets {
    min-height: 220px;
    margin-top: 10px;
}

@keyframes pmb-pulse {
    0%, 100% {
        opacity: 1;
    }

    50% {
        opacity: .55;
    }
}

@media (prefers-reduced-motion: reduce) {
    .pmb-skeleton {
        animation: none;
    }
}

/* --- the class ladder (UX-GUIDELINES section 1): tablet under 900, fold under 700,
       mobile under 500. One class, one shed, least dense information first. --- */

/* The frame needs no width rung of its own: it is a wrapping row, so a narrow viewport
   stacks the number, the selector and the bar in that order against one left edge. The
   860 rung the two-up hero needed went with the hero. */

/* Tablet: the evidence line goes first, least information per pixel on the row. */
@media (max-width: 899.98px) {
    .pmb-col-why {
        display: none;
    }
}

/* Fold: the song name steps aside; jacket and difficulty bubble already say which
   chart it is (the .olb-song-text rule). */
@media (max-width: 699.98px) {
    .pmb-ident-name,
    .pmb-rname {
        display: none;
    }

    .pmb-flip-grid {
        grid-template-columns: 1fr;
    }
}

/* Mobile: scores drop to grade art alone. The art is narrower than the number it
   replaces and the score still rides the row tooltip. */
@media (max-width: 499.98px) {
    .pmb-score-text,
    .pmb-rscore {
        display: none;
    }

    .pmb-hero-value {
        font-size: 38px;
    }

    .pmb-curve-plot {
        height: 128px;
        gap: 1px;
    }

    .pmb-table th,
    .pmb-table td {
        padding-right: 7px;
    }
}

/* Landscape phone: 844 wide and 390 tall. A width rule stacks the hero exactly when
   height is the scarce axis, so this compresses instead. The one rule the width
   ladder cannot express (session-breakdown.md section 5 draws the same line). */
@media (max-height: 520px) and (min-width: 700px) {
    .pmb-hero-value {
        font-size: 34px;
    }

    .pmb-frame {
        gap: 8px 16px;
        padding-bottom: 9px;
    }

    .pmb-frame-nav {
        padding-top: 8px;
    }

    .pmb-curve {
        padding: 10px 12px 11px;
    }

    .pmb-curve-plot {
        height: 84px;
    }

    .pmb-curve-legend {
        display: none;
    }

    .pmb-barcard {
        padding: 7px 10px;
    }

    .pmb-barcard-num {
        font-size: 20px;
    }

    .pmb-barcard-say {
        display: none;
    }
}

/* --- your PUMBILITY titles: three ladders and the per-chart ask --- */
.pmb-rails {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.pmb-rail {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    padding: 13px 15px;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.pmb-rail-top {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}

.pmb-rail-pool {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    padding: 1px 7px;
    border-radius: 3px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 20%, transparent);
}

.pmb-rail-pool.pmb-rail-s {
    color: var(--chart-singles);
    border-color: color-mix(in srgb, var(--chart-singles) 45%, transparent);
}

.pmb-rail-pool.pmb-rail-d {
    color: var(--chart-doubles);
    border-color: color-mix(in srgb, var(--chart-doubles) 45%, transparent);
}

.pmb-rail-value {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 22px;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.pmb-rail-track {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.pmb-rail-bar {
    position: relative;
    height: 9px;
    border-radius: 2px;
    background: var(--mix-surface-muted);
    overflow: hidden;
}

.pmb-rail-fill {
    position: absolute;
    inset: 0 auto 0 0;
    background: var(--mix-primary);
}

/* Three cells, so the distance still to travel sits between the two rungs it is the distance
   across — rather than at the foot of the rail, where it read as a number with no unit beside
   figures that were all per-chart. */
.pmb-rail-ends {
    display: flex;
    align-items: baseline;
    gap: 10px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 11.5px;
    letter-spacing: .07em;
    color: var(--mix-ink-muted);
}

.pmb-rail-ends > :first-child,
.pmb-rail-ends > :last-child {
    flex: 1 1 0;
    min-width: 0;
}

.pmb-rail-ends .pmb-rail-mid {
    flex: 0 0 auto;
    text-align: center;
    color: var(--mix-accent);
}

.pmb-rail-ends .pmb-rail-next {
    color: var(--mix-primary);
    text-align: right;
}

/* The projected pool clearing the ask is the good answer, so it reads as one — the accent
   otherwise on this row means "still to find". */
.pmb-ask-cell.pmb-ask-reach {
    background: color-mix(in srgb, var(--mix-primary) 14%, transparent);
}

.pmb-ask-cell.pmb-ask-reach .pmb-ask-num,
.pmb-ask-cell.pmb-ask-reach .pmb-ask-lbl {
    color: var(--mix-primary);
}

/* The grade rides the same line as its level, always: in a shared caption underneath, three
   levels read as a path — and the low one is the hard one, not the first step. */
.pmb-rail-eg {
    display: inline-block;
    margin-left: 8px;
    white-space: nowrap;
    font-weight: 600;
    color: var(--mix-ink);
}

/* The ask: what the next rung wants of every chart, against what yours are worth now. It
   never assumes a play order, which is the whole reason it replaced counting charts. */
.pmb-ask {
    display: flex;
    align-items: stretch;
    border-radius: 4px;
    overflow: hidden;
    background: var(--mix-surface-muted);
    flex-wrap: wrap;
}

.pmb-ask-cell {
    padding: 7px 12px;
    display: flex;
    flex-direction: column;
    flex: 1 1 130px;
    min-width: 0;
    border-right: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.pmb-ask-cell:last-child {
    border-right: 0;
}

.pmb-ask-lbl {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 10px;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pmb-ask-num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 19px;
    font-variant-numeric: tabular-nums;
    line-height: 1.25;
}

.pmb-ask-cell.pmb-ask-gap {
    background: color-mix(in srgb, var(--mix-accent) 14%, transparent);
}

.pmb-ask-cell.pmb-ask-gap .pmb-ask-num,
.pmb-ask-cell.pmb-ask-gap .pmb-ask-lbl {
    color: var(--mix-accent);
}

.pmb-rail-say {
    font-size: 12.5px;
    color: var(--mix-ink-muted);
    margin: 0;
}

.pmb-rail-say b {
    color: var(--mix-ink);
    font-weight: 600;
}

/* --- where your PUMBILITY comes from --- */
.pmb-wpc {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    padding: 15px 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.pmb-wpc-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.pmb-wpc-title {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
}

.pmb-wpc-total {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

/* True to scale. The plate segment is a hairline because it IS a hairline — widening it to
   be visible would be arguing the opposite of what the section says. It gets its own
   magnified rail below instead. */
.pmb-wpc-stack {
    display: flex;
    height: 34px;
    border-radius: 3px;
    overflow: hidden;
    background: var(--mix-surface-muted);
}

.pmb-wpc-seg {
    display: grid;
    place-items: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    color: var(--mix-primary-contrast);
}

.pmb-wpc-seg.pmb-wpc-level {
    background: var(--mix-primary);
}

.pmb-wpc-seg.pmb-wpc-score {
    background: var(--mix-secondary);
}

.pmb-wpc-seg.pmb-wpc-plate {
    background: var(--mix-accent);
}

.pmb-wpc-keys {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}

.pmb-wpc-key {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding-left: 10px;
    border-left: 3px solid var(--mix-ink-muted);
    min-width: 0;
}

.pmb-wpc-key.pmb-wpc-level {
    border-left-color: var(--mix-primary);
}

.pmb-wpc-key.pmb-wpc-score {
    border-left-color: var(--mix-secondary);
}

.pmb-wpc-key.pmb-wpc-plate {
    border-left-color: var(--mix-accent);
}

.pmb-wpc-k-lbl {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.pmb-wpc-k-num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 23px;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.pmb-wpc-k-pct {
    font-size: 11.5px;
    color: var(--mix-ink-muted);
}

.pmb-wpc-plated {
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    padding-top: 11px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.pmb-wpc-plate-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 12.5px;
}

.pmb-wpc-plate-head strong {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--mix-accent);
}

/* The sliver, on a scale it can be read on: the worst plate on all fifty to the best. */
.pmb-wpc-rail {
    position: relative;
    height: 12px;
    border-radius: 2px;
    background: var(--mix-surface-muted);
    overflow: hidden;
}

.pmb-wpc-rail-fill {
    position: absolute;
    inset: 0 auto 0 0;
    background: var(--mix-accent);
    opacity: .85;
}

.pmb-wpc-say {
    font-size: 13px;
    margin: 0;
}

@media (max-width: 699.98px) {
    .pmb-wpc-keys {
        grid-template-columns: 1fr;
    }
}

/* Source label on a target row. It only renders when the list actually mixes a repriced
   Phoenix 1 score with a peer estimate, so the carried rows read as the harder currency
   they are rather than as one more guess. */
.pmb-src {
    display: inline-block;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 10px;
    letter-spacing: .1em;
    text-transform: uppercase;
    white-space: nowrap;
    padding: 1px 6px;
    border-radius: 3px;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    color: var(--mix-ink-muted);
}

.pmb-src-carry {
    border-color: color-mix(in srgb, var(--mix-accent) 60%, transparent);
    background: color-mix(in srgb, var(--mix-accent) 12%, transparent);
    color: var(--mix-accent);
}


/* MixUnavailableNotice — what a page says when the mix in view cannot answer it. Shared
   rather than page-scoped: .tier-list-cta was declared inside ChartSkills' own <style>
   block, so every other page that reused the class rendered it unstyled. */
.mix-unavailable {
    border: 1px dashed var(--mud-palette-lines-default);
    border-radius: 8px;
    padding: 16px;
    margin: 12px 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: flex-start;
}

.mix-unavailable-detail {
    color: var(--mix-ink-muted);
    max-width: 60ch;
}

.mix-unavailable-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* ============================================================================
   PUMBILITY Calculator (/PumbilityCalculator/{mix}) — docs/design/pumbility-calculator.md
   A static reference page: the formula, its constants, the value tables, the
   level-equivalent ruler and the population answers, all real HTML. What moves
   (the type toggle, the table's contour click, the quick calculator) is
   wwwroot/js/pumbility-calculator.js working on this markup. Tokens only.
   ============================================================================ */

.pc-page {
    display: flex;
    flex-direction: column;
    gap: 34px;
    padding: 16px 0 72px;
}

/* --- hero --- */
.pc-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 18px 32px;
    align-items: end;
}

.pc-eyebrow {
    display: flex;
    gap: 10px;
    align-items: baseline;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 12.5px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.pc-eyebrow .pc-sep {
    color: color-mix(in srgb, var(--mix-ink) 18%, transparent);
}

.pc-eyebrow a {
    color: var(--mix-ink-muted);
    border-bottom: 1px dotted var(--mix-ink-muted);
    text-decoration: none;
}

.pc-eyebrow a:hover {
    color: var(--mix-ink);
}

.pc-h1 {
    margin: 8px 0 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 46px;
    line-height: 1;
    letter-spacing: .005em;
    text-wrap: balance;
}

.pc-h1 span {
    color: var(--mix-primary);
}

.pc-lede {
    max-width: 66ch;
    margin: 12px 0 0;
    font-size: 15px;
    line-height: 1.5;
}

.pc-lede .pc-muted {
    color: var(--mix-ink-muted);
}

/* The Singles/Doubles group heads the run of type-specific sections it governs — the ruler is
   the first thing on the page that changes with it, so it sits right above the ruler's title,
   pulled in against the page gap so the two read as one. */
.pc-typebar {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: -18px;
}

.pc-hint {
    font-size: 11.5px;
    color: var(--mix-ink-muted);
}

.pc-typegroup {
    display: inline-flex;
    border: 1px solid var(--mix-primary);
    border-radius: 4px;
    overflow: hidden;
}

.pc-typegroup button {
    appearance: none;
    background: transparent;
    border: 0;
    color: var(--mix-primary);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: .06em;
    text-transform: uppercase;
    padding: 7px 16px;
    cursor: pointer;
}

.pc-typegroup button + button {
    border-left: 1px solid var(--mix-primary);
}

.pc-typegroup button[aria-pressed="true"] {
    background: var(--mix-primary);
    color: var(--mix-primary-contrast);
}

.pc-typegroup button:focus-visible {
    outline: 2px solid var(--mix-secondary);
    outline-offset: -2px;
}

/* --- shared section vocabulary --- */
.pc-sec {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.pc-sec-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}

.pc-h2 {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 24px;
    letter-spacing: .005em;
    text-wrap: balance;
}

.pc-h2.pc-q {
    font-size: 26px;
}

.pc-h2.pc-q::before {
    content: "Q";
    display: inline-grid;
    place-items: center;
    width: 22px;
    height: 22px;
    margin-right: 10px;
    border-radius: 4px;
    font-size: 14px;
    background: var(--mix-secondary);
    color: var(--mix-primary-contrast);
    vertical-align: 4px;
}

.pc-h3 {
    margin: 0 0 8px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
    letter-spacing: .02em;
}

.pc-sub {
    max-width: 72ch;
    font-size: 13px;
    color: var(--mix-ink-muted);
}

.pc-sub b {
    color: var(--mix-ink);
    font-weight: 600;
}

.pc-card {
    background: var(--mix-surface);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    padding: 16px 18px;
}

.pc-lbl {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.pc-muted {
    color: var(--mix-ink-muted);
}

.pc-foot {
    margin: 10px 0 0;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-mark {
    color: var(--mix-accent);
}

/* --- the formula --- */
.pc-formula {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    gap: 16px;
}

.pc-formula-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 10px;
    margin: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 34px;
    line-height: 1.1;
    letter-spacing: .01em;
}

.pc-formula-line small {
    width: 100%;
    font: 400 15px/1.4 var(--font-body);
    color: var(--mix-ink-muted);
}

.pc-op {
    color: var(--mix-ink-muted);
    font-weight: 600;
}

.pc-t-level {
    color: var(--mix-primary);
    font-style: normal;
}

.pc-t-grade {
    color: var(--mix-secondary);
    font-style: normal;
}

.pc-t-plate {
    color: var(--mix-accent);
    font-style: normal;
}

.pc-terms {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
    margin-top: 16px;
}

.pc-term {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding-left: 10px;
    border-left: 3px solid var(--mix-ink-muted);
}

.pc-term-level {
    border-left-color: var(--mix-primary);
}

.pc-term-grade {
    border-left-color: var(--mix-secondary);
}

.pc-term-plate {
    border-left-color: var(--mix-accent);
}

.pc-term-val {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 20px;
    line-height: 1.15;
}

.pc-term-val small {
    font-size: 13px;
    font-weight: 600;
    color: var(--mix-ink-muted);
}

.pc-term-say {
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-zero {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    align-items: baseline;
    margin-top: 14px;
    font-size: 12.5px;
    color: var(--mix-ink-muted);
}

.pc-zero-item {
    color: var(--mix-ink);
}

.pc-examples {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.pc-example {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 12px;
    align-items: baseline;
    font-size: 13px;
}

.pc-example-who {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
    white-space: nowrap;
}

.pc-example-math {
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.pc-example-math b {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
    color: var(--mix-ink);
}

/* --- the ruler --- */
.pc-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    align-items: center;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-legend i {
    display: inline-block;
    width: 18px;
    height: 8px;
    margin-right: 6px;
    border-radius: 2px;
    vertical-align: 0;
}

.pc-legend i.pc-legend-tail {
    height: 5px;
    opacity: .45;
}

.pc-legend i.pc-legend-anchor {
    width: 2px;
    height: 14px;
    background: var(--mix-ink);
    vertical-align: -3px;
}

.pc-ruler {
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr) 46px;
    gap: 0 10px;
    margin-top: 12px;
}

.pc-ruler-axis {
    grid-column: 2;
    position: relative;
    height: 22px;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-ruler-axis span {
    position: absolute;
    bottom: 4px;
    transform: translateX(-50%);
}

.pc-ruler-axis .pc-ruler-cap {
    left: 0;
    transform: none;
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.pc-ruler-axis .pc-ruler-cap-past {
    transform: translateX(6px);
    opacity: .7;
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.pc-ruler-lbl {
    height: 22px;
    margin-bottom: 4px;
    line-height: 22px;
    text-align: right;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
}

.pc-ruler-track {
    position: relative;
    height: 22px;
    margin-bottom: 4px;
}

.pc-ruler-grid {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.pc-ruler-grid.pc-ruler-grid-5 {
    background: color-mix(in srgb, var(--mix-ink) 18%, transparent);
}

.pc-ruler-past {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    background: repeating-linear-gradient(135deg, transparent 0 4px, color-mix(in srgb, var(--mix-ink) 6%, transparent) 4px 5px);
}

.pc-seg {
    position: absolute;
    top: 5px;
    height: 12px;
}

.pc-seg-tail {
    top: 8px;
    height: 6px;
    opacity: .45;
    background: var(--plate-rg);
}

.pc-seg-copper {
    background: var(--plate-fg);
}

.pc-seg-silver {
    background: var(--plate-tg);
}

.pc-seg-gold {
    background: var(--plate-sg);
}

.pc-seg-ice {
    background: var(--plate-ug);
}

.pc-ruler-track:hover .pc-seg {
    filter: brightness(1.15);
}

.pc-ruler-anchor {
    position: absolute;
    top: 2px;
    width: 2px;
    height: 18px;
    background: var(--mix-ink);
    transform: translateX(-1px);
}

.pc-ruler-end {
    height: 22px;
    margin-bottom: 4px;
    line-height: 22px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}

.pc-ruler-foot {
    margin: 10px 0 0;
    max-width: 80ch;
    font-size: 12.5px;
    color: var(--mix-ink-muted);
}

.pc-ruler-foot b {
    color: var(--mix-ink);
    font-weight: 600;
}

/* --- the value table --- */
.pc-tablewrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    border-radius: 6px;
    background: var(--mix-surface);
}

.pc-tablewrap-plain {
    border: 0;
    border-radius: 0;
    background: transparent;
}

.pc-vt {
    width: 100%;
    min-width: 900px;
    border-collapse: separate;
    border-spacing: 0;
    font-variant-numeric: tabular-nums;
}

.pc-vt th,
.pc-vt td {
    padding: 0;
    text-align: center;
    font-size: 12.5px;
}

.pc-vt thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    padding: 8px 4px 6px;
    background: var(--mix-surface);
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
    letter-spacing: .02em;
}

.pc-vt .pc-floor {
    display: block;
    margin-top: 1px;
    font: 400 10.5px/1.3 var(--font-body);
    color: var(--mix-ink-muted);
    letter-spacing: 0;
}

.pc-metal {
    display: block;
    width: 60%;
    height: 3px;
    margin: 4px auto 0;
    border-radius: 2px;
}

.pc-vt thead th.pc-lv,
.pc-vt tbody td.pc-lv {
    position: sticky;
    left: 0;
    z-index: 2;
    text-align: left;
    padding-left: 12px;
    background: var(--mix-surface);
}

.pc-vt thead th.pc-lv {
    z-index: 3;
}

.pc-vt tbody td.pc-lv {
    white-space: nowrap;
    border-right: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 15px;
}

.pc-vt tbody td.pc-lv small {
    margin-left: 6px;
    font-size: 11px;
    font-weight: 600;
    color: var(--mix-ink-muted);
}

.pc-vt tbody td.pc-lv sup {
    margin-left: 2px;
    font-size: 10px;
    color: var(--mix-accent);
}

.pc-vt tbody td.pc-v {
    height: 30px;
    cursor: pointer;
    border: 2px solid transparent;
    border-radius: 3px;
    transition: transform .08s;
}

.pc-vt tbody td.pc-v:hover {
    position: relative;
    z-index: 1;
    transform: scale(1.06);
}

.pc-vt tbody td.pc-v.pc-hit {
    border-color: var(--mix-ink);
    box-shadow: 0 0 0 1px var(--mix-bg) inset;
}

.pc-vt tbody td.pc-v.pc-pick {
    border-color: var(--mix-secondary);
    box-shadow: 0 0 0 2px var(--mix-secondary), 0 0 12px var(--mix-secondary);
}

.pc-vt tbody td.pc-v.pc-far {
    opacity: .35;
}

.pc-vt tbody td.pc-v-muted {
    background: var(--mix-surface-muted);
    color: var(--mix-ink-muted);
    cursor: default;
}

.pc-vt tbody td.pc-n {
    padding: 0 10px;
    white-space: nowrap;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-vt tbody tr.pc-coop td.pc-lv {
    border-top: 1px dashed color-mix(in srgb, var(--mix-ink) 18%, transparent);
}

/* The value ramp: one hue, the mix's primary, from the surface up — a set of classes on the
   tokens rather than an inline colour, so the ratchet reads it and a theme can re-hue it. */
.pc-ramp-0 { background: color-mix(in oklab, var(--mix-primary) 6%, var(--mix-surface-muted)); color: var(--mix-ink); }
.pc-ramp-1 { background: color-mix(in oklab, var(--mix-primary) 15%, var(--mix-surface-muted)); color: var(--mix-ink); }
.pc-ramp-2 { background: color-mix(in oklab, var(--mix-primary) 24%, var(--mix-surface-muted)); color: var(--mix-ink); }
.pc-ramp-3 { background: color-mix(in oklab, var(--mix-primary) 33%, var(--mix-surface-muted)); color: var(--mix-ink); }
.pc-ramp-4 { background: color-mix(in oklab, var(--mix-primary) 42%, var(--mix-surface-muted)); color: var(--mix-ink); }
.pc-ramp-5 { background: color-mix(in oklab, var(--mix-primary) 51%, var(--mix-surface-muted)); color: var(--mix-primary-contrast); }
.pc-ramp-6 { background: color-mix(in oklab, var(--mix-primary) 60%, var(--mix-surface-muted)); color: var(--mix-primary-contrast); }
.pc-ramp-7 { background: color-mix(in oklab, var(--mix-primary) 70%, var(--mix-surface-muted)); color: var(--mix-primary-contrast); }
.pc-ramp-8 { background: color-mix(in oklab, var(--mix-primary) 80%, var(--mix-surface-muted)); color: var(--mix-primary-contrast); }
.pc-ramp-9 { background: color-mix(in oklab, var(--mix-primary) 90%, var(--mix-surface-muted)); color: var(--mix-primary-contrast); }

.pc-contour-cap {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    align-items: baseline;
    min-height: 20px;
    font-size: 13px;
    color: var(--mix-ink-muted);
}

.pc-contour-cap b {
    font-family: var(--font-display);
    font-size: 16px;
    color: var(--mix-ink);
}

.pc-contour-cap .pc-eq {
    color: var(--mix-ink);
}

.pc-contour-cap button {
    appearance: none;
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    border-radius: 3px;
    padding: 2px 8px;
    font-size: 11px;
    color: var(--mix-ink-muted);
    cursor: pointer;
}

.pc-table-foot {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-rampkey {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.pc-rampkey i {
    display: inline-block;
    width: 90px;
    height: 8px;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--mix-surface-muted), var(--mix-primary));
}

/* --- the constants --- */
/* Stacked, never side by side: the grade ladder is seventeen columns and the plate table nine,
   and neither fits in a share of the row without a scroller. Full width, the ladder's grade
   columns also line up under the value table's. */
.pc-consts {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
}

.pc-ct {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.pc-ct th,
.pc-ct td {
    padding: 6px 4px;
    text-align: center;
    font-size: 12.5px;
    border-bottom: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.pc-ct th {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13.5px;
}

.pc-ct td.pc-rl,
.pc-ct th.pc-rl {
    text-align: left;
    padding-right: 8px;
    white-space: nowrap;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--mix-ink-muted);
}

.pc-ct td.pc-diff {
    color: var(--mix-ink);
    font-weight: 600;
}

.pc-ct td.pc-same {
    color: var(--mix-ink-muted);
}

.pc-ct td.pc-floor-cell {
    font-size: 11px;
    color: var(--mix-ink-muted);
}

@media (max-width: 860px) {
    .pc-hero {
        grid-template-columns: 1fr;
    }

    .pc-h1 {
        font-size: 38px;
    }

    .pc-formula {
        grid-template-columns: 1fr;
    }

    .pc-formula-line {
        font-size: 28px;
    }

    .pc-terms {
        grid-template-columns: 1fr;
    }
}

@media (prefers-reduced-motion: reduce) {
    .pc-vt tbody td.pc-v {
        transition: none;
    }
}

/* --- the comparison (this mix in primary, the other in secondary) --- */
.pc-cmp-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-cmp-legend i {
    display: inline-block;
    width: 18px;
    height: 8px;
    margin-right: 6px;
    border-radius: 2px;
    vertical-align: 0;
}

.pc-cmp-swatch-other {
    background: var(--mix-secondary);
}

.pc-cmp-swatch-mine {
    background: var(--mix-primary);
}

.pc-cmp {
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr) 62px;
    gap: 0 10px;
    margin-top: 12px;
}

.pc-cmp-axis {
    grid-column: 2;
    position: relative;
    height: 22px;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-cmp-axis span {
    position: absolute;
    bottom: 4px;
    transform: translateX(-50%);
}

.pc-cmp-lbl {
    height: 40px;
    margin-bottom: 6px;
    line-height: 40px;
    text-align: right;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
}

.pc-cmp-track {
    position: relative;
    height: 40px;
    margin-bottom: 6px;
}

.pc-cmp-grid {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: color-mix(in srgb, var(--mix-ink) 10%, transparent);
}

.pc-cmp-bar {
    position: absolute;
    height: 14px;
    border-radius: 0 3px 3px 0;
}

.pc-cmp-bar-other {
    top: 4px;
    background: var(--mix-secondary);
}

.pc-cmp-bar-mine {
    top: 22px;
    background: var(--mix-primary);
}

.pc-cmp-bar span {
    position: absolute;
    left: calc(100% + 6px);
    top: -1px;
    white-space: nowrap;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 12.5px;
    color: var(--mix-ink);
}

.pc-cmp-anchor {
    position: absolute;
    top: 2px;
    bottom: 2px;
    width: 2px;
    background: var(--mix-ink);
    transform: translateX(-1px);
}

/* Where the two curves cross, said under the bars that show it. */
.pc-cmp-note {
    margin: 12px 0 0;
    padding-top: 10px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    font-size: 12.5px;
    color: var(--mix-ink-muted);
}

.pc-cmp-facts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.pc-cmp-fact {
    display: flex;
    flex-direction: column;
    gap: 3px;
    border-left: 3px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
}

.pc-cmp-fact.pc-cmp-hero {
    border-left-color: var(--mix-primary);
    background: color-mix(in srgb, var(--mix-primary) 7%, var(--mix-surface));
}

.pc-cmp-fact.pc-cmp-hero .pc-lbl {
    color: var(--mix-ink);
}

.pc-cmp-pair {
    display: flex;
    gap: 14px;
    align-items: baseline;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 22px;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.pc-cmp-hero .pc-cmp-pair {
    font-size: 26px;
}

.pc-cmp-other {
    color: var(--mix-secondary);
}

.pc-cmp-mine {
    color: var(--mix-primary);
}

.pc-cmp-vs {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .1em;
    color: var(--mix-ink-muted);
}

.pc-cmp-say {
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-cmp-say b {
    color: var(--mix-ink);
    font-weight: 600;
}

.pc-answer {
    margin: 0;
    max-width: 78ch;
    font-size: 14px;
    line-height: 1.5;
}

.pc-answer b {
    color: var(--mix-ink);
    font-weight: 600;
}

.pc-answer .pc-n {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
}

@media (max-width: 860px) {
    .pc-cmp-facts {
        grid-template-columns: 1fr;
    }
}

/* A type block is a run of sections; the script hides the type not selected. The explicit
   [hidden] rule matters: the flex display below would otherwise beat the attribute. */
.pc-type-block {
    display: flex;
    flex-direction: column;
    gap: 34px;
}

.pc-type-block[hidden] {
    display: none;
}

/* --- the quick calculator --- */
.pc-calc {
    display: grid;
    grid-template-columns: auto auto auto minmax(0, 1fr);
    gap: 14px 22px;
    align-items: end;
}

.pc-calc-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.pc-calc select {
    appearance: none;
    min-width: 130px;
    padding: 8px 32px 8px 10px;
    background: var(--mix-surface-muted);
    color: var(--mix-ink);
    border: 1px solid color-mix(in srgb, var(--mix-ink) 18%, transparent);
    border-radius: 4px;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
    background-image: linear-gradient(45deg, transparent 50%, var(--mix-ink-muted) 50%), linear-gradient(135deg, var(--mix-ink-muted) 50%, transparent 50%);
    background-position: calc(100% - 16px) 55%, calc(100% - 11px) 55%;
    background-size: 5px 5px;
    background-repeat: no-repeat;
}

.pc-calc select:focus-visible {
    outline: 2px solid var(--mix-secondary);
    outline-offset: 1px;
}

.pc-calc-static {
    padding: 8px 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 16px;
    color: var(--mix-ink-muted);
}

.pc-calc-out {
    display: flex;
    flex-direction: column;
    gap: 4px;
    justify-self: end;
    text-align: right;
}

.pc-calc-big {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 44px;
    line-height: 1;
    letter-spacing: .01em;
    font-variant-numeric: tabular-nums;
}

.pc-calc-math {
    font-size: 13px;
    color: var(--mix-ink-muted);
    font-variant-numeric: tabular-nums;
}

.pc-calc-eq {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    padding-top: 10px;
    border-top: 1px solid color-mix(in srgb, var(--mix-ink) 10%, transparent);
    font-size: 13px;
    color: var(--mix-ink-muted);
}

.pc-calc-eq:empty {
    display: none;
}

.pc-calc-eq b {
    color: var(--mix-ink);
    font-weight: 600;
}

@media (max-width: 860px) {
    .pc-calc {
        grid-template-columns: 1fr 1fr;
    }

    .pc-calc-out {
        grid-column: 1 / -1;
        justify-self: start;
        text-align: left;
    }
}

/* --- the population answers --- */
.pc-pop-bands {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin: 0;
    font-size: 12px;
    color: var(--mix-ink-muted);
}

.pc-pop-bands b {
    color: var(--mix-ink);
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: .04em;
}

.pc-plate-rail {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The plate ladder as one bar, Rough Game to Perfect Game: every plate a segment in its own
   plate colour, sized by its bonus, carrying what it is worth on the reference chart. */
.pc-plate-track {
    position: relative;
    display: flex;
    height: 44px;
    border-radius: 4px;
    background: var(--mix-surface-muted);
    overflow: hidden;
}

.pc-plate-seg {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 0;
    overflow: hidden;
    /* The plate fills are light in every theme and the page ground is dark in every theme, so
       the ground colour is the ink that reads on all of them. */
    color: var(--mix-bg);
    font-family: var(--font-display);
    line-height: 1.15;
    border-right: 2px solid var(--mix-surface);
}

.pc-plate-seg:last-child {
    border-right: 0;
}

.pc-plate-seg-name {
    font-weight: 700;
    font-size: 12.5px;
    letter-spacing: .04em;
}

.pc-plate-seg-val {
    font-weight: 600;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}

/* Where the tracked pools' average plate falls on the same scale. */
.pc-plate-marker {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--mix-ink);
}

.pc-plate-poolrow {
    position: relative;
    height: 16px;
}

.pc-plate-pool {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    white-space: nowrap;
    font-size: 11.5px;
    color: var(--mix-ink);
}

.pc-plate-ends {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 11.5px;
    color: var(--mix-ink-muted);
}

/* On a phone the seven segments are too narrow to carry their labels: the bar stays coloured
   and the labels move into a list beneath it. */
.pc-plate-list {
    display: none;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (max-width: 640px) {
    .pc-plate-track {
        height: 14px;
    }

    .pc-plate-seg span {
        display: none;
    }

    .pc-plate-poolrow {
        height: auto;
    }

    .pc-plate-pool {
        position: static;
        transform: none;
        white-space: normal;
    }

    .pc-plate-list {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
        gap: 4px 12px;
        font-size: 12px;
    }

    .pc-plate-list i {
        display: inline-block;
        width: 10px;
        height: 10px;
        margin-right: 6px;
        border-radius: 2px;
        vertical-align: -1px;
    }

    .pc-plate-list b {
        font-variant-numeric: tabular-nums;
    }
}
