/* =========================================================================
   RallyTrack design system
   ----
   Source of truth: docs/rallytrack-mockups.html (theme tokens, lines 14–69;
   cell-state CSS, lines 936–951) and design.md §11.4.4.
   Behavioural reference: design.md §11.4.2, §11.4.4.
   Dark-mode by default. Tokens are exposed as CSS custom properties so
   per-component razor.css files can pick them up.
   ========================================================================= */

:root {
    /* Surfaces — recalibrated per §11.4.4 (v2.13.16): the layered surfaces are
       lifted (same ~221° cool blue-grey hue, same inter-layer spacing) so panels
       separate more clearly from the base and read better in bright light. Base
       and rally red are unchanged. */
    --bg-base:        #0B0E13;
    --bg-surface:     #222733;
    --bg-elevated:    #2A303E;
    --bg-elevated-2:  #333A4A;
    --bg-stripe:      #181D27;

    /* Lines */
    --line:           #2A3140;
    --line-strong:    #3A4254;

    /* Text */
    --fg:             #ECEEF2;
    --fg-muted:       #A6ADBB;
    --fg-dim:         #6B7382;
    --fg-faint:       #4A5160;

    /* Signal colours — used surgically. */
    --rally-red:      #E1232C;
    --rally-red-dim:  #B81B23;
    --rally-red-glow: rgba(225, 35, 44, 0.18);

    --amber:          #F4A21A;
    --amber-dim:      #B97907;
    --amber-glow:     rgba(244, 162, 26, 0.16);

    --green:          #2BB673;
    --green-dim:      #1B8451;
    --green-glow:     rgba(43, 182, 115, 0.16);

    --cyan:           #38BDF8;
    --cyan-dim:       #0EA5E9;

    --pink:           #EA4F8E;
    --pink-glow:      rgba(234, 79, 142, 0.18);

    /* §11.4.4 / v2.13.2: purple cell tone for RallySafe-event manual
       overrides. Stronger than the green/amber tones because overrides are
       exceptional and should attract the eye. */
    --purple:         #B084EE;
    --purple-glow:    rgba(176, 132, 238, 0.20);

    /* §11.1.3 / v2.13.4: warm copper-red bronze for the 3rd-place podium
       row. Replaces the previous #c08552 tan-copper which sat too close to
       the amber-gold of the 1st-place colour and was hard to distinguish at
       small sizes. */
    --bronze:         #b85c38;
    --bronze-glow:    rgba(184, 92, 56, 0.10);

    /* Type */
    --font-display:   "Saira Condensed", system-ui, sans-serif;
    --font-body:      "Geist", system-ui, -apple-system, sans-serif;
    --font-mono:      "JetBrains Mono", ui-monospace, monospace;

    /* Radius */
    --r-sm: 4px;
    --r-md: 6px;
    --r-lg: 10px;
    --r-xl: 14px;

    /* Spacing scale */
    --s-1:  4px;
    --s-2:  8px;
    --s-3: 12px;
    --s-4: 16px;
    --s-5: 24px;
    --s-6: 32px;
    --s-7: 48px;
    --s-8: 72px;

    /* Shadows */
    --shadow-1: 0 1px 0 rgba(255, 255, 255, 0.04) inset, 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-2: 0 8px 24px rgba(0, 0, 0, 0.5), 0 1px 0 rgba(255, 255, 255, 0.03) inset;
}

/* ── Base elements ──────────────────────────────────────────────────────── */

html, body {
    background: var(--bg-base);
    color: var(--fg);
    font-family: var(--font-body);
    font-size: 14.5px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

::selection {
    background: var(--rally-red);
    color: white;
}

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: 0.005em;
    margin: 0;
}

/* The Blazor <FocusOnNavigate> component pulls focus to the page <h1>
   after every navigation, which is good for screen-reader announcements
   but draws a visible browser focus outline around the heading by
   default. Headings are not interactive targets — keyboard users don't
   tab to them — so suppressing the outline entirely is the right call;
   screen readers still announce the heading via the focus shift. */
h1:focus, h2:focus, h3:focus, h4:focus,
h1:focus-visible, h2:focus-visible, h3:focus-visible, h4:focus-visible {
    outline: none;
}

a {
    color: var(--cyan);
    text-decoration: none;
}

a:hover {
    color: var(--cyan-dim);
    text-decoration: underline;
}

/* ── Bootstrap overrides ────────────────────────────────────────────────── */
/* The app still leans on Bootstrap 5 for layout primitives (grid, utilities,
   forms). We override its surface and typography defaults so it sits inside
   the dark-mode design system without leaking light theme colours. */

.btn {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
    border-radius: var(--r-md);
}

.btn-primary,
.btn-primary:focus {
    background-color: var(--rally-red);
    border-color: var(--rally-red);
    color: white;
}

.btn-primary:hover,
.btn-primary:active {
    background-color: var(--rally-red-dim);
    border-color: var(--rally-red-dim);
    color: white;
}

.btn-outline-secondary {
    color: var(--fg-muted);
    border-color: var(--line-strong);
    background: transparent;
}

.btn-outline-secondary:hover {
    background: var(--bg-elevated-2);
    border-color: var(--line-strong);
    color: var(--fg);
}

.btn-secondary {
    background: var(--bg-elevated);
    border-color: var(--line-strong);
    color: var(--fg);
}

.btn-secondary:hover {
    background: var(--bg-elevated-2);
    border-color: var(--line-strong);
    color: var(--fg);
}

.btn-danger {
    background: var(--rally-red);
    border-color: var(--rally-red);
    color: white;
}

.btn-danger:hover {
    background: var(--rally-red-dim);
    border-color: var(--rally-red-dim);
}

.form-control,
.form-select {
    background-color: var(--bg-elevated);
    border-color: var(--line);
    color: var(--fg);
    font-family: var(--font-mono);
}

.form-control:focus,
.form-select:focus {
    background-color: var(--bg-elevated);
    border-color: var(--rally-red);
    box-shadow: 0 0 0 0.2rem var(--rally-red-glow);
    color: var(--fg);
}

.form-control::placeholder {
    color: var(--fg-dim);
}

.form-label,
.col-form-label {
    color: var(--fg-muted);
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 12px;
    font-weight: 600;
}

.form-text {
    color: var(--fg-dim);
}

.table {
    color: var(--fg);
    border-color: var(--line);
}

.table > :not(caption) > * > * {
    background-color: transparent;
    border-bottom-color: var(--line);
    color: var(--fg);
}

.table-bordered > :not(caption) > * > * {
    border-color: var(--line);
}

.table-dark,
.table > thead.table-dark {
    --bs-table-bg: var(--bg-elevated);
    --bs-table-color: var(--fg);
    --bs-table-border-color: var(--line-strong);
}

.table-secondary {
    --bs-table-bg: var(--bg-elevated-2);
    --bs-table-color: var(--fg);
}

.table-striped > tbody > tr:nth-of-type(odd) > * {
    background-color: var(--bg-stripe);
    color: var(--fg);
}

.table-hover > tbody > tr:hover > * {
    background-color: var(--bg-elevated);
    color: var(--fg);
}

.card {
    background-color: var(--bg-surface);
    border-color: var(--line);
    color: var(--fg);
    border-radius: var(--r-lg);
}

.card-header {
    background-color: var(--bg-elevated);
    border-bottom-color: var(--line);
    color: var(--fg);
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
}

.modal-content {
    background-color: var(--bg-surface);
    border-color: var(--line);
    color: var(--fg);
}

.modal-header,
.modal-footer {
    border-color: var(--line);
}

.alert-danger {
    background-color: rgba(225, 35, 44, 0.12);
    border-color: var(--rally-red);
    color: var(--fg);
}

.alert-warning {
    background-color: var(--amber-glow);
    border-color: var(--amber);
    color: var(--fg);
}

.alert-success {
    background-color: var(--green-glow);
    border-color: var(--green);
    color: var(--fg);
}

.alert-info {
    background-color: rgba(56, 189, 248, 0.12);
    border-color: var(--cyan);
    color: var(--fg);
}

.text-muted {
    color: var(--fg-muted) !important;
}

.text-danger {
    color: var(--rally-red) !important;
}

.text-success {
    color: var(--green) !important;
}

.text-warning {
    color: var(--amber) !important;
}

.text-info {
    color: var(--cyan) !important;
}

.bg-light {
    background-color: var(--bg-elevated) !important;
    color: var(--fg);
}

.bg-dark {
    background-color: var(--bg-base) !important;
}

.bg-secondary {
    background-color: var(--bg-elevated-2) !important;
}

.bg-danger {
    background-color: var(--rally-red) !important;
}

.badge {
    font-family: var(--font-display);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    border-radius: 999px;
}

.nav-tabs {
    border-bottom-color: var(--line);
}

.nav-tabs .nav-link {
    color: var(--fg-muted);
    border-color: transparent;
    background: transparent;
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
}

.nav-tabs .nav-link:hover {
    color: var(--fg);
    border-color: transparent;
}

.nav-tabs .nav-link.active {
    color: var(--fg);
    background: transparent;
    border-color: transparent transparent var(--rally-red);
    border-bottom-width: 2px;
}

.dropdown-menu {
    background-color: var(--bg-surface);
    border-color: var(--line);
    color: var(--fg);
}

.dropdown-item {
    color: var(--fg);
}

.dropdown-item:hover,
.dropdown-item:focus {
    background-color: var(--bg-elevated);
    color: var(--fg);
}

.dropdown-divider {
    border-color: var(--line);
}

.pagination .page-link {
    background-color: var(--bg-elevated);
    border-color: var(--line);
    color: var(--fg-muted);
}

.pagination .page-link:hover {
    background-color: var(--bg-elevated-2);
    color: var(--fg);
}

.pagination .page-item.active .page-link {
    background-color: var(--rally-red);
    border-color: var(--rally-red);
    color: white;
}

.list-group-item {
    background-color: var(--bg-surface);
    border-color: var(--line);
    color: var(--fg);
}

hr {
    border-color: var(--line);
    opacity: 1;
}

/* ── Utility classes ────────────────────────────────────────────────────── */

.mono,
.num {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.display-font {
    font-family: var(--font-display);
}

.upper {
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.kicker {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: var(--rally-red);
}

/* ── Component primitives ───────────────────────────────────────────────── */

.rt-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    border: 1px solid;
}

.rt-badge-live     { color: var(--rally-red); border-color: var(--rally-red); background: var(--rally-red-glow); }
.rt-badge-prov     { color: var(--amber);     border-color: var(--amber);     background: var(--amber-glow); }
.rt-badge-verified { color: var(--green);     border-color: var(--green);     background: var(--green-glow); }
.rt-badge-otl      { color: var(--fg-dim);    border-color: var(--line-strong); background: transparent; }

.rt-toolbar-group {
    display: inline-flex;
    background: var(--bg-elevated);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    overflow: hidden;
}

.rt-toolbar-btn {
    padding: 7px 13px;
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-muted);
    background: transparent;
    border: none;
    border-right: 1px solid var(--line);
    cursor: pointer;
}

.rt-toolbar-btn:last-child { border-right: none; }
.rt-toolbar-btn.active     { background: var(--rally-red); color: white; }
.rt-toolbar-btn:hover:not(.active) { background: var(--bg-elevated-2); color: var(--fg); }

/* ── Event card + banner ────────────────────────────────────────────────── */
/* Used by the home hero, the event landing page, and any "spotlight one event"
   surface. Reference: docs/rallytrack-mockups.html lines 377–453. */

.event-card {
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    overflow: hidden;
}

.event-banner {
    position: relative;
    padding: var(--s-7) var(--s-6);
    background:
        linear-gradient(120deg, rgba(225, 35, 44, 0.18), transparent 50%),
        linear-gradient(0deg, var(--bg-surface), transparent),
        radial-gradient(800px 400px at 100% 0%, rgba(56, 189, 248, 0.08), transparent 60%);
    border-bottom: 1px solid var(--line);
}

.event-banner::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: repeating-linear-gradient(90deg, transparent 0 60px, rgba(255, 255, 255, 0.025) 60px 61px);
    pointer-events: none;
}

.event-banner-inner {
    position: relative;
    z-index: 1;
}

.event-status {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 10px;
    background: var(--rally-red-glow);
    border: 1px solid var(--rally-red);
    color: var(--rally-red);
    border-radius: 999px;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.event-status.upcoming {
    background: transparent;
    border-color: var(--fg-muted);
    color: var(--fg-muted);
}

.event-status.recent {
    background: var(--green-glow);
    border-color: var(--green);
    color: var(--green);
}

/* v2.13.5 R2 / §5.16: state-machine-driven badge colours. Pending covers
   ParcFermé, FinalisingProvisional, and ProvisionalPublished — yellow tells
   the visitor the classification is not yet final. Final is the green you'd
   expect for a completed, published event (same family as .recent above —
   .recent stays for legacy callers but new code uses .rt-status-final). */
.event-status.rt-status-pending {
    background: var(--amber-glow);
    border-color: var(--amber);
    color: var(--amber);
}

.event-status.rt-status-final {
    background: var(--green-glow);
    border-color: var(--green);
    color: var(--green);
}

/* .event-status .dot was replaced by the canonical .live-dot utility in
   v2.13.0 (see Home.razor's HeroState.Live branch). The pulse animation,
   colour, and shape now live in one place. */

.event-banner h1 {
    font-size: clamp(36px, 5vw, 56px);
    text-transform: uppercase;
    letter-spacing: -0.005em;
    line-height: 0.95;
    margin-top: var(--s-3);
    margin-bottom: var(--s-3);
    /* Flag and title are separate flex items so the title wraps as its own
       left-aligned block — line 2 ("RALLYSPRINT 2026") sits under line 1's
       first word rather than under the flag. The flag's own margin-right
       supplies the gap; baseline keeps it sitting on the first line. */
    display: flex;
    align-items: baseline;
}

/* min-width:0 lets the title flex item shrink and wrap instead of forcing
   horizontal overflow from its longest word. */
.event-banner h1 .event-title-text {
    min-width: 0;
}

.event-banner h1 .accent {
    color: var(--rally-red);
}

.event-banner .subtitle {
    color: var(--fg-muted);
    font-size: 16px;
}

.event-banner-meta {
    margin-top: var(--s-5);
    display: grid;
    /* auto-fit so the row reflows from 5 to 3 to 2 to 1 tile per row as the
       viewport shrinks. Each tile is at least 160px so values like
       "Car 11 · Walters / Crowley" don't wrap mid-name. */
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--s-5);
    padding-top: var(--s-4);
    border-top: 1px solid var(--line-strong);
}

.event-banner-meta .item .label {
    font-family: var(--font-mono);
    font-size: 10.5px;
    color: var(--fg-dim);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    white-space: nowrap;
}

/* Wide tile — spans two grid columns so longer values (Winner / Leader
   crew names like "Car 13 · RANDO / BECKWITH") stay on one line. The
   neighbouring stat tiles compress slightly to make room. Collapses to
   a single column on narrow viewports where the grid is already 1-2
   tracks wide. */
.event-banner-meta .item.wide {
    grid-column: span 2;
}

@media (max-width: 768px) {
    .event-banner-meta .item.wide {
        grid-column: auto;
    }
}

.event-banner-meta .item .value {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 600;
    margin-top: 2px;
}

.event-banner-meta .item .value.mono {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: 18px;
}

/* ── Manufacturer icons (entry list + results table) ────────────────────── */
/* Mockup reference: docs/rallytrack-mockups.html lines 1140–1157. Renders at
   16px next to the vehicle make/model. The fallback _unknown.png is a flat
   greyscale silhouette. */

.mfr-icon {
    width: 16px;
    height: 16px;
    display: inline-block;
    vertical-align: -3px;
    margin-right: 6px;
    color: var(--fg-muted);
    flex-shrink: 0;
    object-fit: contain;
}

/* The public entry list and the results table both show the manufacturer logo
   at 22px (larger than the inline 16px default) for easier scanning of the
   vehicle column. */
.rt-entries-table .mfr-icon,
.results-frozen .mfr-icon {
    width: 22px;
    height: 22px;
    vertical-align: middle;
}

/* ── Admin sidebar visibility (driven by wwwroot/js/sidebar.js) ─────────── */
/* The toggle hamburger in AdminTopBar adds/removes these classes on <body>.
   - sb-collapsed: desktop user has hidden the sidebar (persisted in
     localStorage so it survives navigations).
   - sb-open: mobile drawer is currently visible.
   Component-scoped CSS can't target <body>, so these rules live globally. */

body.sb-collapsed .rt-admin-sidebar {
    display: none;
}

@media (max-width: 768px) {
    body.sb-open .rt-admin-sidebar {
        transform: translateX(0);
    }
}

/* ── Public results table (§10.8) ───────────────────────────────────────── */

/* Prevent the page from scrolling horizontally when the results table is wider
   than the viewport; the table's own .results-scroll handles the overflow. */
main.rt-public-main {
    overflow-x: hidden;
}

/* Results page: override the scoped PublicLayout max-width/padding so the
   layout fills the full viewport. Specificity (0,2,3) beats the scoped
   rule's (0,2,0), so no !important needed. */
html body main.rt-public-main:has(.rt-results-layout) {
    max-width: none;
    padding: 0;
    margin: 0;
    width: 100%;
}

/* Full-viewport results layout. Fills the viewport below the topbar (64px)
   so the table scrolls internally rather than the page scrolling. The padding
   is inside the height calculation via box-sizing: border-box. */
.rt-results-layout {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 64px);
    padding: var(--s-4) var(--s-5);
    box-sizing: border-box;
    overflow: hidden;
}

.rt-results-layout .public-page-grid {
    flex: 1;
    min-height: 0;
    align-items: stretch;   /* override default 'start' so the card fills the grid row height */
}

.rt-results-layout .results-card {
    display: flex;
    flex-direction: column;
}

.rt-results-layout .results-scroll {
    flex: 1;
    min-height: 0;
    max-height: none;   /* override the 70vh cap from the base rule */
}

/* On narrow viewports (phones in either orientation + tablets in portrait)
   the sidebar collapses to a drawer and the table takes the full width; revert
   to content-height layout so the table is not artificially truncated. The
   1024px cut-off covers phone landscape (up to ~932px) and tablet portrait,
   where the desktop both-sides column freeze cannot fit. */
@media (max-width: 1024px) {
    .rt-results-layout {
        height: auto;
        overflow: visible;
        overflow-x: hidden;
    }

    .rt-results-layout .results-scroll {
        max-height: 60vh;
    }
}

.results-card {
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
}

.results-toggle-bar {
    display: flex;
    align-items: center;
    gap: var(--s-5);
    padding: var(--s-3) var(--s-4);
    border-bottom: 1px solid var(--line);
    background: var(--bg-elevated);
    flex-wrap: wrap;
}

.results-toggle-bar .toggle-group {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    flex-wrap: wrap;
}

.results-toggle-bar .toggle-label {
    font-family: var(--font-display);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-faint);
}

.results-toggle-bar .check-row {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--fg);
    cursor: pointer;
}

.results-toggle-bar .check-row input[type="checkbox"] {
    appearance: none;
    width: 13px;
    height: 13px;
    border: 1px solid var(--line-strong);
    border-radius: 3px;
    background: var(--bg-surface);
    position: relative;
    flex-shrink: 0;
}

.results-toggle-bar .check-row input[type="checkbox"]:checked {
    background: var(--rally-red);
    border-color: var(--rally-red);
}

.results-toggle-bar .check-row input[type="checkbox"]:checked::after {
    content: "";
    position: absolute;
    left: 3px;
    top: -1px;
    width: 4px;
    height: 8px;
    border: solid white;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.results-toggle-bar .filter-summary {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--fg-muted);
}

.results-scroll {
    overflow-x: auto;
    max-height: 70vh;
    overflow-y: auto;
}

table.results-frozen {
    border-collapse: separate;
    border-spacing: 0;
    font-size: 12.5px;
    /* width: max-content lets the table size to its column min-widths so the
       sticky offsets resolve correctly. The parent .results-scroll handles
       the horizontal overflow. */
    width: max-content;
    min-width: 100%;
}

table.results-frozen thead th {
    background: var(--bg-elevated);
    color: var(--fg-dim);
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    text-align: left;
    padding: 10px 10px;
    border-bottom: 1px solid var(--line-strong);
    position: sticky;
    top: 0;
    z-index: 3;
    white-space: nowrap;
}

table.results-frozen tbody td {
    padding: 10px 10px;
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
    background: var(--bg-surface);
    white-space: nowrap;
}

table.results-frozen tbody tr:hover td {
    background: var(--bg-elevated);
}

/* Frozen-left columns: cumulative left offsets. The Entrant column was removed
   and Crew / Vehicle / Class condensed so the frozen block ends at 512px (was
   780px), giving the scrolling stage/results columns ~270px more room. Crew,
   Vehicle and Class clip with an ellipsis rather than wrapping to two lines. */
.results-frozen .col-pos     { position: sticky; left: 0;    z-index: 2; width: 50px;  min-width: 50px; }
.results-frozen .col-car     { position: sticky; left: 50px; z-index: 2; width: 54px;  min-width: 54px; }
.results-frozen .col-crew    { position: sticky; left: 104px; z-index: 2; width: 176px; min-width: 176px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.results-frozen .col-vehicle { position: sticky; left: 280px; z-index: 2; width: 168px; min-width: 168px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; box-shadow: 1px 0 0 var(--line); }
.results-frozen .col-class   { position: sticky; left: 448px; z-index: 2; width: 64px;  min-width: 64px;  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; box-shadow: 2px 0 4px rgba(0,0,0,0.25); }

.results-frozen thead .col-pos,
.results-frozen thead .col-car,
.results-frozen thead .col-crew,
.results-frozen thead .col-vehicle,
.results-frozen thead .col-class { z-index: 4; }

/* Left frozen tbody cells must have an explicit opaque background. Without it
   the cells are transparent and scrolling stage columns bleed through visually.
   The existing hover rule (tbody tr:hover td, specificity 0,2,4) beats this
   rule (0,2,3) so the row highlight still works correctly on hover. */
table.results-frozen tbody td.col-pos,
table.results-frozen tbody td.col-car,
table.results-frozen tbody td.col-crew,
table.results-frozen tbody td.col-vehicle,
table.results-frozen tbody td.col-class {
    background: var(--bg-surface);
}

/* Frozen-right columns. "Total Time"/"Total Points" (col-total) is always
   visible; "Total Penalties" (col-pen), +Leader and +Behind are toggleable
   (default: pen on, leader/behind off — §10.8). Pen pins immediately left of
   Total when shown. Right offsets are computed from width variables that each
   toggleable column contributes only while visible, so the visible columns stay
   flush to the right edge in every combination. (col-total is a fixed 100px, so
   col-pen's offset adds a literal 100px for it.) */
.results-frozen { --wb: 0px; --wl: 0px; }
.results-frozen:not(.hide-behind) { --wb: 100px; }
.results-frozen:not(.hide-leader) { --wl: 100px; }

.results-frozen .col-pen     { position: sticky; z-index: 2; width: 100px; min-width: 100px; right: calc(var(--wb) + var(--wl) + 100px); background: var(--bg-surface); text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* Total-penalty values are rally-red; a crew with no penalty shows a grey dash. */
.results-frozen td.col-pen          { color: var(--rally-red); }
.results-frozen td.col-pen.is-empty { color: var(--fg-faint); }
.results-frozen .col-total   { position: sticky; z-index: 2; width: 100px; min-width: 100px; right: calc(var(--wb) + var(--wl)); background: var(--bg-surface); }
.results-frozen .col-leader  { position: sticky; z-index: 2; width: 100px; min-width: 100px; right: var(--wb); background: var(--bg-surface); }
.results-frozen .col-behind  { position: sticky; z-index: 2; width: 100px; min-width: 100px; right: 0; background: var(--bg-surface); }

/* Freeze-edge shadow sits on the leftmost visible frozen-right column: that is
   Total when Pen is hidden, otherwise Pen. */
.results-frozen .col-total { box-shadow: -2px 0 4px rgba(0,0,0,0.25); }
.results-frozen:not(.hide-pen) .col-total { box-shadow: none; }
.results-frozen:not(.hide-pen) .col-pen   { box-shadow: -2px 0 4px rgba(0,0,0,0.25); }

/* Hide the toggleable frozen-right columns when off (hide-pen lives with the
   other toggle-visibility rules below). */
.results-frozen.hide-leader .col-leader { display: none; }
.results-frozen.hide-behind .col-behind { display: none; }

.results-frozen thead .col-pen,
.results-frozen thead .col-total,
.results-frozen thead .col-leader,
.results-frozen thead .col-behind { z-index: 4; }
/* "Total Penalties" is the only frozen-right header that can exceed its column
   width; let it wrap (rather than overflow and break the sticky offsets) and
   keep its header in the standard dim colour instead of the body's amber. */
.results-frozen thead .col-pen { white-space: normal; line-height: 1.15; color: var(--fg-dim); }

/* Scrollable middle columns */
.results-frozen .col-stage   { width: 96px; min-width: 96px; text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.results-frozen .col-split   { width: 70px; min-width: 70px; text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--fg-muted); font-size: 11.5px; }

.results-frozen .col-total,
.results-frozen .col-leader,
.results-frozen .col-behind { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* Stage position-in-brackets styling */
.results-frozen .stage-pos {
    color: var(--fg-faint);
    font-size: 10.5px;
    margin-left: 4px;
}

.results-frozen .stage-pos.win {
    color: var(--amber);
    font-weight: 700;
}

/* Position cell */
.results-frozen td.col-pos {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 14px;
}
.results-frozen td.col-pos.p1 { color: var(--amber); }
.results-frozen td.col-pos.p2 { color: #b8c1ce; }
.results-frozen td.col-pos.p3 { color: var(--bronze); }

/* DNF row dimming. Do NOT use opacity on the td — that makes the cell's
   background semi-transparent and lets scrolled stage columns bleed through
   the sticky frozen columns. Fade text colour instead, and apply opacity only
   to inline icons / pills which sit on top of (already-opaque) backgrounds. */
.results-frozen tr.dnf-row td { color: var(--fg-muted); }
.results-frozen tr.dnf-row td.col-pos { color: var(--fg-faint); }
.results-frozen tr.dnf-row .mfr-icon,
.results-frozen tr.dnf-row .stage-pos {
    opacity: 0.55;
}

/* DNF / DNS / ELT / DSQ status shown as plain text in the same monospace font
   and size as a time value (inherited from .col-total), no box or chip — bronze
   and bold so it reads as a first-class value and stands out against the dimmed
   row (the row-dimming opacity rule above deliberately excludes it). */
.results-frozen .status-pill {
    font-family: var(--font-mono);
    font-weight: 700;
    color: var(--bronze);
}

/* Toggle visibility classes — flipped by public-results.js */
.results-frozen.hide-stage    .col-stage,
.results-frozen.hide-stage    thead .col-stage { display: none; }
.results-frozen.hide-split    .col-split,
.results-frozen.hide-split    thead .col-split { display: none; }
.results-frozen.hide-stagepos .stage-pos { display: none; }
.results-frozen.hide-pen      .col-pen,
.results-frozen.hide-pen      thead .col-pen { display: none; }
.results-frozen.hide-penaltystage .col-penstage,
.results-frozen.hide-penaltystage thead .col-penstage { display: none; }
.results-frozen.hide-pointsstage  .col-pointsstage,
.results-frozen.hide-pointsstage  thead .col-pointsstage { display: none; }

/* Per-control penalty columns and per-stage points columns live in the
   scrolling middle region (not frozen). Penalty headers stay the standard dim
   header colour (inherited); penalty values are rally-red, and a control with
   no penalty shows a grey dash. */
.results-frozen .col-penstage   { width: 92px; min-width: 92px; text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 11.5px; }
.results-frozen td.col-penstage          { color: var(--rally-red); }
.results-frozen td.col-penstage.is-empty { color: var(--fg-faint); }
.results-frozen .col-pointsstage { width: 64px; min-width: 64px; text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: var(--fg-muted); font-size: 11.5px; }

/* The body cells above use a slightly smaller mono font; keep the header text
   at the standard 10px so these column headers don't read larger than the rest
   of the header row. */
.results-frozen thead th.col-split,
.results-frozen thead th.col-penstage,
.results-frozen thead th.col-pointsstage { font-size: 10px; }

/* Display-mode-scoped toolbar toggles (public-results.js sets mode-regularity
   on the results card when a Regularity class is the active filter). */
.results-card.mode-regularity .toggle-ss-only { display: none; }
.results-card:not(.mode-regularity) .toggle-reg-only { display: none; }

/* ── Narrow-viewport column freeze (§10.8) ──────────────────────────────────
   The desktop layout freezes columns on BOTH sides (# / Car / Crew / Vehicle /
   Class on the left; Total Penalties / Total Time / +Leader / +Behind on the
   right). When the viewport is narrower than the two frozen blocks combined,
   the opaque frozen-right cells paint straight over the frozen-left ones — on a
   phone that hid the driver names entirely (only the first letter showed).
   Below 1024px we therefore keep only # and Car pinned and let every other
   column scroll normally, so nothing is ever overlapped. Column headers keep
   their sticky TOP (the header row still pins on vertical scroll) but drop the
   horizontal pin. */
@media (max-width: 1024px) {
    .results-frozen tbody td.col-crew,
    .results-frozen tbody td.col-vehicle,
    .results-frozen tbody td.col-class,
    .results-frozen tbody td.col-pen,
    .results-frozen tbody td.col-total,
    .results-frozen tbody td.col-leader,
    .results-frozen tbody td.col-behind {
        position: static;
        box-shadow: none;
    }

    .results-frozen thead th.col-crew,
    .results-frozen thead th.col-vehicle,
    .results-frozen thead th.col-class,
    .results-frozen thead th.col-pen,
    .results-frozen thead th.col-total,
    .results-frozen thead th.col-leader,
    .results-frozen thead th.col-behind {
        position: sticky;
        left: auto;
        right: auto;
        box-shadow: none;
    }
}

/* ── Public page grid + sidebar (§10.7) ─────────────────────────────────── */

.public-page-grid {
    display: grid;
    /* minmax(0, 1fr) lets the content column shrink below the natural width
       of a wide table so .results-scroll becomes the horizontal scroller
       rather than the grid track stretching to fit. */
    grid-template-columns: 240px minmax(0, 1fr);
    gap: var(--s-5);
    align-items: start;
}

/* §10.7 collapse: when the sidebar is collapsed (public-sidebar.js toggles
   .is-collapsed from localStorage), shrink the grid track to a rail so the
   results table gets the freed width. */
.public-page-grid:has(.public-sidebar.is-collapsed) {
    grid-template-columns: 56px minmax(0, 1fr);
}

@media (max-width: 1024px) {
    /* The second selector overrides the desktop :has(.is-collapsed) rail rule
       (higher specificity) so a visitor who collapsed the sidebar on desktop
       doesn't get a stray empty rail track once it becomes a drawer. */
    .public-page-grid,
    .public-page-grid:has(.public-sidebar.is-collapsed) {
        grid-template-columns: minmax(0, 1fr);
    }
}

.public-sidebar {
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: var(--s-4);
    position: sticky;
    top: var(--s-4);
    transition: width 0.18s ease-out;
}

.public-sidebar.is-collapsed .sidebar-body {
    display: none;
}

.public-sidebar .sidebar-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--s-4);
    padding-bottom: var(--s-3);
    border-bottom: 1px solid var(--line);
}

.public-sidebar .sidebar-head h3 {
    font-size: 13px;
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg);
    margin: 0;
}

.public-sidebar.is-collapsed .sidebar-head h3 {
    display: none;
}

.public-sidebar .sidebar-collapse {
    cursor: pointer;
    color: var(--fg-faint);
    background: none;
    border: none;
    padding: 4px;
    font-family: var(--font-mono);
    font-size: 14px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}
.public-sidebar .sidebar-collapse:hover { color: var(--fg); }

/* Chevron when expanded; funnel icon when collapsed to the rail. */
.public-sidebar .sidebar-collapse-funnel { display: none; }
.public-sidebar.is-collapsed .sidebar-collapse-chevron { display: none; }
.public-sidebar.is-collapsed .sidebar-collapse-funnel { display: inline-block; }

/* Collapsed rail: centre the funnel, drop the head divider and side padding. */
.public-sidebar.is-collapsed {
    padding-left: var(--s-2);
    padding-right: var(--s-2);
}
.public-sidebar.is-collapsed .sidebar-head {
    justify-content: center;
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: none;
}

.public-sidebar .sidebar-group {
    margin-bottom: var(--s-5);
}

.public-sidebar .sidebar-group:last-of-type {
    margin-bottom: 0;
}

.public-sidebar .sidebar-group-label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-faint);
    margin-bottom: var(--s-2);
}

.public-sidebar .check-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 0;
    cursor: pointer;
    font-size: 13px;
    color: var(--fg);
}

/* §10.8 server-side scope links (competition class / heat). Styled to read like
   the radio rows — a dot that fills when active — but they navigate (enhanced
   nav) to re-scope the table server-side rather than filtering client-side. */
.public-sidebar .scope-link {
    text-decoration: none;
    color: var(--fg-muted);
}
.public-sidebar .scope-link:hover { color: var(--fg); }
.public-sidebar .scope-link .scope-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid var(--line-strong);
    background: var(--bg-elevated);
    flex-shrink: 0;
    box-sizing: border-box;
}
.public-sidebar .scope-link.is-active { color: var(--fg); font-weight: 600; }
.public-sidebar .scope-link.is-active .scope-dot {
    border-color: var(--rally-red);
    background: radial-gradient(circle, var(--rally-red) 0 3.5px, transparent 4.5px);
}
.public-sidebar .sidebar-tag {
    margin-left: 6px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--amber);
    border: 1px solid var(--amber);
    border-radius: 4px;
    padding: 0 4px;
    opacity: 0.85;
}

.public-sidebar .check-row input[type="checkbox"],
.public-sidebar .check-row input[type="radio"] {
    appearance: none;
    width: 14px;
    height: 14px;
    border: 1px solid var(--line-strong);
    border-radius: 3px;
    background: var(--bg-elevated);
    position: relative;
    flex-shrink: 0;
    cursor: pointer;
}

.public-sidebar .check-row input[type="radio"] {
    border-radius: 50%;
}

.public-sidebar .check-row input[type="checkbox"]:checked,
.public-sidebar .check-row input[type="radio"]:checked {
    background: var(--rally-red);
    border-color: var(--rally-red);
}

.public-sidebar .check-row input[type="checkbox"]:checked::after {
    content: "";
    position: absolute;
    left: 3px;
    top: 0;
    width: 4px;
    height: 8px;
    border: solid white;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.public-sidebar .check-row input[type="radio"]:checked::after {
    content: "";
    position: absolute;
    left: 3px;
    top: 3px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: white;
}

.public-sidebar .sidebar-count {
    margin-left: auto;
    color: var(--fg-faint);
    font-family: var(--font-mono);
    font-size: 11px;
}

.public-sidebar .sidebar-reset {
    color: var(--cyan);
    font-family: var(--font-mono);
    font-size: 12px;
    text-decoration: none;
    margin-top: var(--s-3);
    display: inline-block;
    /* Reset default <button> styling so the element matches the previous
       <a> appearance. v2.13.5: switched to <button> to keep Blazor's
       enhanced navigation from following the link. */
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
}

.public-sidebar .sidebar-reset:hover,
.public-sidebar .sidebar-reset:focus-visible {
    text-decoration: underline;
    text-underline-offset: 3px;
    outline: none;
}

.public-sidebar .filter-summary {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--fg-muted);
    background: var(--bg-elevated);
    padding: 6px 8px;
    border-radius: 4px;
    margin-top: var(--s-2);
}

/* Mobile drawer / dropdown */
.public-sidebar-mobile-toggle {
    display: none;
    background: var(--bg-elevated);
    border: 1px solid var(--line);
    color: var(--fg);
    padding: 10px 14px;
    border-radius: var(--r-md);
    font-family: var(--font-display);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    cursor: pointer;
    margin-bottom: var(--s-3);
}

/* Drawer mode for phones (either orientation) and tablets in portrait. Above
   1024px the sidebar is an inline collapsible rail; at or below it the sidebar
   is hidden behind the "Filters" toggle so the results table gets the full
   width (the inline 240px rail otherwise squeezes the table badly on landscape
   phones and tablet portrait). */
@media (max-width: 1024px) {
    .public-sidebar-mobile-toggle {
        display: inline-flex;
        /* Sit ABOVE the drawer (grid order) so the "Filters" button reads as an
           accordion header: tap to expand the panel below it, tap again to
           collapse. Without this the button rendered as a second stray "Filters"
           bar UNDER the open panel. */
        order: -1;
    }

    .public-sidebar {
        display: none;
        position: relative;
        top: auto;
    }

    .public-sidebar.is-open {
        display: block;
        margin-bottom: var(--s-4);
    }

    /* Hide the whole drawer head on mobile: its "Filters" title just duplicates
       the toggle button above, and the « rail-collapse control is a desktop-only
       affordance that does nothing useful in a drawer. */
    .public-sidebar .sidebar-head {
        display: none;
    }

    .public-sidebar.is-open .sidebar-body {
        margin-top: var(--s-2);
    }
}

/* ── Public event detail page (§10.2) ───────────────────────────────────── */

/* "← All Events" ghost/outline button above the hero (§10.2). Reads as
   navigation rather than a primary action — border, transparent background,
   muted text. Does not compete visually with the hero card below it. */
.rt-event-back {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-bottom: var(--s-3);
    padding: 5px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--fg-dim);
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    transition: border-color 120ms ease-out, color 120ms ease-out, background 120ms ease-out;
}

.rt-event-back:hover,
.rt-event-back:focus-visible {
    border-color: var(--line-strong);
    background: var(--bg-elevated);
    color: var(--fg);
    text-decoration: none;
}

.rt-event-hero {
    margin-bottom: var(--s-4);
}

/* Hero banner with Conditions docked into the top-right area per Chris's
   feedback. Banner inner stays a single column; the conditions aside sits
   to the right of it on wide viewports, drops below on narrow. */
.rt-event-hero-banner {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--s-5);
    align-items: start;
}

@media (min-width: 900px) {
    .rt-event-hero-banner {
        grid-template-columns: 1fr 320px;
    }
}

.rt-event-hero-conditions {
    min-width: 0;
}

.rt-event-hero-conditions .rt-weather-panel {
    margin-bottom: 0;
}

.rt-schedule-heat-label {
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--fg);
    margin: var(--s-3) 0 var(--s-2);
}

.rt-schedule-heat-label:first-of-type {
    margin-top: 0;
}

.rt-event-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-5);
    border-bottom: 1px solid var(--line);
    margin-bottom: var(--s-5);
    padding: 0 var(--s-2);
}

/* Same treatment as .chrome-event-menu a.active — fg text colour, red
   border-bottom only; deliberately not red text. */
.rt-event-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: var(--s-3) 0;
    color: var(--fg-muted);
    text-decoration: none;
    font-family: var(--font-display);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    border-bottom: 2px solid transparent;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.rt-event-tab:hover {
    color: var(--fg);
    text-decoration: none;
}

.rt-event-tab.active {
    color: var(--fg);
    border-bottom-color: var(--rally-red);
}

.rt-section-h {
    font-family: var(--font-display);
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-faint);
    margin: 0 0 var(--s-3);
}

.rt-event-about,
.rt-event-schedule,
.rt-event-classes,
.rt-event-conditions,
.rt-event-where {
    margin-bottom: var(--s-5);
}

.rt-event-about p {
    color: var(--fg);
    line-height: 1.55;
    margin: 0 0 var(--s-3);
}

.rt-link {
    color: var(--cyan);
    text-decoration: none;
    font-family: var(--font-mono);
    font-size: 13px;
}

.rt-link:hover {
    color: var(--cyan-dim);
    text-decoration: none;
}

.rt-schedule-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--s-3);
}

@media (max-width: 900px) {
    .rt-schedule-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 480px) {
    .rt-schedule-grid {
        grid-template-columns: 1fr;
    }
}

.rt-schedule-tile {
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
}

.rt-schedule-tile-label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-faint);
    margin-bottom: var(--s-2);
}

.rt-schedule-tile-value {
    font-size: 14px;
    color: var(--fg);
    display: flex;
    align-items: baseline;
    gap: var(--s-2);
    flex-wrap: wrap;
}

.rt-schedule-tile-time {
    /* Match the date portion in size + colour so the line reads as one
       cohesive "Sat 23 May 08:20" value rather than a value with a faint
       afterthought. */
    color: var(--fg);
    font-size: 14px;
}

.rt-schedule-tile-sub {
    margin-top: 4px;
    color: var(--fg-dim);
    font-size: 11px;
}

/* Public itinerary table (§10.2 Itinerary tab). */
.rt-itin-head {
    display: flex;
    align-items: center;
    gap: var(--s-4);
    margin-bottom: var(--s-5);
}
.rt-itin-head h1 {
    font-size: 28px;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    margin: 0;
}
.rt-itin-back {
    font-family: var(--font-display);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--fg-muted);
    text-decoration: none;
    padding: 6px 12px;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
}
.rt-itin-back:hover {
    color: var(--fg);
    background: var(--bg-elevated);
    text-decoration: none;
}
.rt-itin-panel {
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
}
.rt-itin-empty {
    padding: var(--s-5);
    color: var(--fg-muted);
}
.rt-itin-table {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--font-body);
    font-size: 13px;
}
.rt-itin-table thead th {
    padding: var(--s-3) var(--s-4);
    text-align: left;
    font-family: var(--font-display);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-muted);
    background: var(--bg-elevated);
    border-bottom: 1px solid var(--line);
}
.rt-itin-table thead th.col-code  { width: 100px; }
.rt-itin-table thead th.col-time  { width: 150px; }
.rt-itin-table thead th.col-dist  { width: 100px; text-align: right; }
.rt-itin-table tbody td {
    padding: var(--s-3) var(--s-4);
    border-top: 1px solid var(--line);
}
.rt-itin-table tbody td.col-dist  { text-align: right; }
.rt-itin-table tbody tr.rt-itin-stage td {
    background: var(--bg-elevated);
    font-weight: 500;
}

/* Timezone abbreviation pill rendered next to scheduled times per §5.15.
   Used on schedule tiles, itinerary times, and anywhere else event-local
   times are shown so visitors know which zone they're reading. */
.rt-tz-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 0 6px;
    border-radius: var(--r-sm);
    background: var(--bg-elevated);
    color: var(--fg-muted);
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.06em;
    vertical-align: 2px;
}

/* ── Competition classes chip list (§10.2 v2.12.2) ─────────────────────── */

.rt-classes-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-2);
}

.rt-class-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: 8px 12px;
}

.rt-class-chip-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    flex-shrink: 0;
}

.rt-class-chip-name {
    font-family: var(--font-display);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--fg);
}

.rt-class-chip-count {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--fg-faint);
}

.rt-event-map {
    width: 100%;
    height: 320px;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: var(--bg-elevated);
}

/* ── Shared topbar shell (§11.0) ────────────────────────────────────────── */
/* Used by both AdminTopBar.razor and PublicChrome.razor. Lives in the global
   stylesheet rather than a scoped razor.css so the two chromes share the
   exact same layout. */

.rt-topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    height: 64px;
    display: flex;
    align-items: center;
    gap: var(--s-4);
    padding: 0 var(--s-5);
    background: linear-gradient(180deg, rgba(20, 24, 33, 0.85), rgba(11, 14, 19, 0.85));
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--line);
}

.rt-topbar-toggle {
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    width: 36px;
    height: 36px;
    padding: 0;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    cursor: pointer;
}

.rt-topbar-toggle span {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--fg-muted);
}

.rt-topbar-brand {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    color: var(--fg);
    text-decoration: none;
}

.rt-topbar-brand:hover {
    color: var(--fg);
    text-decoration: none;
}

.rt-topbar-title {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--s-2);
    font-family: var(--font-display);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--fg-muted);
    min-width: 0;
}

.rt-topbar-title.start {
    justify-content: flex-start;
}

.rt-crumb-link {
    color: var(--fg-muted);
    text-decoration: none;
}

.rt-crumb-link:hover {
    color: var(--fg);
    text-decoration: none;
}

.rt-crumb-sep {
    color: var(--fg-dim);
}

.rt-crumb-current {
    color: var(--fg);
    font-weight: 600;
}

@media (max-width: 640.98px) {
    .rt-topbar {
        padding: 0 var(--s-3);
    }
    .logo-img {
        height: 28px;
    }
}

/* ── Chrome topbar brand glyph + wordmark (§11.0 concern 6) ─────────────── */
/* Shared between admin chrome (AdminTopBar) and the public slim chrome.
   Mockup reference: docs/rallytrack-mockups.html lines 1294-1316. */

.logo-mark {
    display: flex;
    align-items: center;
    gap: var(--s-2);
    text-decoration: none;
    color: var(--fg);
}

.logo-mark:hover {
    color: var(--fg);
    text-decoration: none;
}

.logo-glyph {
    width: 40px;
    height: 40px;
    background: linear-gradient(135deg, var(--rally-red) 0%, #6a0d12 100%);
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 2px 8px rgba(184, 27, 35, 0.35);
}

.logo-text {
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--fg);
}

.logo-text-accent {
    color: var(--rally-red);
}

.logo-img {
    height: 36px;
    width: auto;
    display: block;
    flex-shrink: 0;
}

/* ── Chrome clock + countdown (§11.0 concern 7) ─────────────────────────── */
/* Both ticked by wwwroot/js/chrome-clock.js. Shared across admin + public
   chrome. Mockup reference: docs/rallytrack-mockups.html lines 1327-1390. */

.chrome-clock {
    display: flex;
    flex-direction: row;
    align-items: center;
    line-height: 1.1;
    border-right: 1px solid var(--line);
    padding-right: var(--s-4);
    margin-right: var(--s-2);
    gap: 12px;
}

/* Main / event sub-clocks each stack their time over their tz label. */
.chrome-clock .clock-main,
.chrome-clock .clock-event {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
}

.chrome-clock .now {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--fg);
    font-variant-numeric: tabular-nums;
}

/* Public chrome bumps the clock up a notch since the centre slot has more
   room to breathe than the admin breadcrumb path. */
.rt-topbar-public .chrome-clock .now {
    font-size: 15px;
}

.rt-topbar-public .chrome-clock {
    border-right: none;
    padding-right: 0;
    margin-right: 0;
    align-items: center;
    text-align: center;
}

.rt-topbar-public .chrome-clock .tz {
    margin-top: 3px;
}

.rt-topbar-public .chrome-countdown {
    margin-right: var(--s-8);  /* wider gap between countdown and event clock */
    margin-left: var(--s-8);   /* wider gap between visitor clock and countdown */
    align-items: center;
    text-align: center;
}

.rt-topbar-public .chrome-countdown .time {
    font-size: 15px;            /* match .chrome-clock .now size */
}

.chrome-clock .tz {
    font-family: var(--font-display);
    font-size: 10px;
    color: var(--fg-faint);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-top: 2px;
}

/* Event clock — a separate ChromeEventClock component placed on the OTHER
   SIDE of the countdown by PublicChrome / AdminTopBar. Same dimensions
   and typography as the visitor clock so the two read as a balanced pair
   around the central "LIVE NOW" pivot. */
.chrome-clock-event {
    border-right: none;
    padding-right: 0;
    margin-right: 0;
    margin-left: 0;
}

.chrome-clock .event-now {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--fg);
    font-variant-numeric: tabular-nums;
}

.rt-topbar-public .chrome-clock .event-now {
    font-size: 15px;            /* match .chrome-clock .now public size */
}

.chrome-clock .event-tz {
    font-family: var(--font-display);
    font-size: 10px;
    color: var(--fg-faint);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-top: 1px;
}

.chrome-countdown {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    line-height: 1.1;
    margin-right: var(--s-2);
}

/* §5.16 48-hour window: the countdown renders into the DOM while still outside
   its window (so chrome-clock.js can reveal it on the boundary crossing without
   a reload) but stays hidden until then. */
.chrome-countdown.is-hidden { display: none; }

.chrome-countdown .label {
    font-family: var(--font-display);
    font-size: 10px;
    color: var(--fg-faint);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    /* Sits below the time, mirroring the .chrome-clock .tz position. */
    margin-top: 2px;
}

.chrome-countdown .time {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--rally-red);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.chrome-countdown .time.live {
    color: var(--rally-red);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* The pulsing dot beside "Live now" comes from an inline .live-dot span
   rendered by ChromeCountdown.razor (server-side) and by chrome-clock.js
   (client-side transition). The bespoke ::before pseudo-element used in
   v2.12.x was removed in v2.13.0 PR 7 — every "live now" indicator across
   the site now shares the same .live-dot definition. */

/* Small viewports: keep the visitor clock visible (and the countdown when one
   is running) but stack them vertically in the centre so they fit the 64px
   topbar. The second-line labels (tz, "Countdown until…") and the secondary
   event clock are dropped to save the limited width/height — the time values
   are what matter at a glance on a phone. */
@media (max-width: 768px) {
    .rt-topbar-public .rt-topbar-title {
        flex-direction: column;
        justify-content: center;
        gap: 1px;
        min-width: 0;
    }

    .rt-topbar-public .chrome-clock,
    .rt-topbar-public .chrome-countdown {
        margin: 0;
        padding: 0;
        border: none;
    }

    .rt-topbar-public .chrome-clock .now,
    .rt-topbar-public .chrome-countdown .time {
        font-size: 12px;
    }

    /* Drop the second-line labels and the secondary event clock on phones. */
    .rt-topbar-public .chrome-clock .tz,
    .rt-topbar-public .chrome-countdown .label,
    .rt-topbar-public .chrome-clock-event {
        display: none;
    }
}

/* Very small phones: drop the wordmark (keep the logo image) so the centre
   clock block has room. */
@media (max-width: 480px) {
    .rt-topbar-public .logo-text {
        display: none;
    }
}

/* ── Weather and conditions panel (§10.6) ───────────────────────────────── */

.rt-weather-panel {
    display: flex;
    flex-direction: column;
    gap: var(--s-3);
    padding: var(--s-4);
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    color: var(--fg);
    margin-bottom: var(--s-4);
}

.rt-weather-panel-empty {
    color: var(--fg-muted);
}

/* Panel header label: "Conditions" (live/past) or "Forecasted Weather" (upcoming within 5 days). */
.rt-weather-panel-header {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--fg-faint);
}

/* Top row: icon + body + rain tile */
.rt-weather-top {
    display: flex;
    align-items: flex-start;
    gap: var(--s-4);
}

.rt-weather-icon-wrap {
    flex-shrink: 0;
    color: var(--fg);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
}

.rt-weather-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.rt-weather-summary {
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 600;
    display: flex;
    align-items: baseline;
    gap: var(--s-3);
}

.rt-weather-temp {
    color: var(--fg-muted);
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 400;
}

.rt-weather-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-3);
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--fg-muted);
}

/* Prominent rain-chance tile — sits on the right of the top row. */
.rt-weather-rain {
    flex-shrink: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
    text-align: center;
    min-width: 96px;
}

.rt-weather-rain-high {
    background: rgba(56, 189, 248, 0.10);
    border-color: rgba(56, 189, 248, 0.45);
}

.rt-weather-rain-value {
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 700;
    color: var(--cyan);
    line-height: 1;
}

.rt-weather-rain-label {
    margin-top: 4px;
    font-family: var(--font-mono);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-muted);
}

/* Operator-set track conditions block — labelled and emphasised. */
.rt-weather-track {
    background: var(--bg-elevated);
    border-left: 3px solid var(--rally-red);
    border-radius: var(--r-sm);
    padding: var(--s-3) var(--s-4);
}

.rt-weather-track-label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg-faint);
    margin-bottom: 4px;
}

.rt-weather-track-body {
    color: var(--fg);
    font-size: 13px;
    line-height: 1.4;
}

.rt-weather-stamp {
    color: var(--fg-dim);
    font-family: var(--font-mono);
    font-size: 11px;
}

@media (max-width: 480px) {
    .rt-weather-top {
        flex-wrap: wrap;
    }
    .rt-weather-rain {
        width: 100%;
    }
}

/* ── Country flags (event listings) ─────────────────────────────────────── */
/* Used by Components/Shared/CountryFlag.razor. Sized in em so it scales
   with the surrounding text. object-fit: cover handles graceful cropping at
   the 1.78:1 aspect ratio. Mockup reference: lines 1242-1252. */

.flag {
    display: inline-block;
    height: 0.9em;
    width: calc(0.9em * 1.78);
    vertical-align: -0.08em;
    margin-right: 0.4em;
    border-radius: 1px;
    object-fit: cover;
    flex-shrink: 0;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06);
}

/* ── User icon + dropdown menu (admin top bar + public header) ──────────── */
/* Mockup reference: docs/rallytrack-mockups.html lines 1111–1202. */

.user-icon-wrap {
    position: relative;
    flex-shrink: 0;
}

.user-icon {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--rally-red) 0%, #6a0d12 100%);
    color: var(--fg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.04em;
    cursor: pointer;
    border: 1px solid var(--line-strong);
    padding: 0;
}

.user-icon:hover {
    border-color: var(--rally-red);
}

.user-icon.signed-out {
    background: var(--bg-elevated-2);
    color: var(--fg-muted);
    border-color: var(--line);
}

.user-icon.signed-out:hover {
    color: var(--fg);
    border-color: var(--line-strong);
}

.user-icon.signed-out svg {
    width: 22px;
    height: 22px;
    fill: currentColor;
    display: block;
}

.user-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-2);
    min-width: 240px;
    padding: var(--s-2) 0;
    font-family: var(--font-body);
    font-size: 13px;
    z-index: 60;
}

.user-menu-email {
    padding: var(--s-3) var(--s-4);
    color: var(--fg-muted);
    font-family: var(--font-mono);
    font-size: 12px;
    word-break: break-all;
}

.user-menu-divider {
    height: 1px;
    background: var(--line);
    margin: 0;
}

.user-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    padding: var(--s-2) var(--s-4);
    color: var(--fg);
    font-family: var(--font-body);
    font-size: 13px;
    cursor: pointer;
    text-decoration: none;
}

.user-menu-item:hover {
    background: var(--bg-elevated-2);
    color: var(--fg);
    text-decoration: none;
}

.user-menu-item-destructive {
    color: var(--rally-red);
}

.user-menu-item-destructive:hover {
    color: var(--rally-red);
}

.user-menu form {
    margin: 0;
}

/* ── Help icon + Help dialogs (§11.0) ───────────────────────────────────── */
/* The help icon is a matched pair with the user icon: same 36px circle, the
   muted-circle treatment of the signed-out user icon, same border + hover. The
   popover reuses .user-menu / .user-menu-item so the two read identically. */
.help-icon-wrap {
    position: relative;
    flex-shrink: 0;
}

.help-icon {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--bg-elevated-2);
    color: var(--fg-muted);
    border: 1px solid var(--line);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
}

.help-icon:hover {
    color: var(--fg);
    border-color: var(--line-strong);
}

.help-icon svg {
    width: 22px;
    height: 22px;
    display: block;
}

/* Modal shell — native <dialog> in the top layer. The element itself is a
   transparent wrapper sized to the card; ::backdrop dims the page. Elevated
   surface, rounded, subtle border per §11.0. */
.rt-dialog {
    border: none;
    background: transparent;
    padding: 0;
    margin: auto;
    max-width: 100vw;
    max-height: 100vh;
    color: var(--fg);
}

.rt-dialog::backdrop {
    background: rgba(0, 0, 0, 0.55);
}

.rt-dialog-card {
    position: relative;
    width: min(92vw, var(--rt-dialog-max, 440px));
    max-height: calc(100vh - 4rem);
    overflow-y: auto;
    background: var(--bg-elevated);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-2);
    padding: var(--s-6);
    font-family: var(--font-body);
}

.rt-dialog-close-form {
    margin: 0;
}

.rt-dialog-close {
    position: absolute;
    top: var(--s-3);
    right: var(--s-3);
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: var(--r-sm);
    color: var(--fg-muted);
    cursor: pointer;
    padding: 0;
}

.rt-dialog-close:hover {
    color: var(--fg);
    background: var(--bg-elevated-2);
}

.rt-dialog-close svg {
    width: 18px;
    height: 18px;
    display: block;
}

/* About dialog */
.rt-about {
    text-align: center;
}

.rt-about-logo {
    width: 180px;
    max-width: 70%;
    height: auto;
    display: block;
    margin: var(--s-1) auto var(--s-4);
}

.rt-about-version {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--fg-muted);
}

.rt-about-divider {
    height: 1px;
    background: var(--line);
    margin: var(--s-4) 0;
}

.rt-about-copy {
    font-size: 12px;
    color: var(--fg-muted);
}

/* Support block: a centred card with left-aligned content; the two contact
   rows align on their icons so the labels share a left edge. */
.rt-about-support {
    margin: var(--s-5) auto 0;
    max-width: 320px;
    text-align: left;
    background: var(--bg-elevated-2);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    padding: var(--s-3) var(--s-4);
}

.rt-about-support-lead {
    margin: 0 0 var(--s-2);
    font-size: 13px;
    color: var(--fg-muted);
}

.rt-about-contact {
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: var(--s-1) 0;
    font-size: 13px;
    color: var(--fg-muted);
    text-decoration: none;
}

.rt-about-contact:hover {
    color: var(--fg);
    text-decoration: none;
}

.rt-about-contact svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* Privacy dialog — readable measure, scrollable via the card's overflow. */
.rt-dialog-title {
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 18px;
    color: var(--fg);
    margin: 0 0 var(--s-4);
}

.rt-privacy p {
    margin: 0 0 var(--s-3);
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--fg-muted);
}

.rt-privacy p:last-child {
    margin-bottom: 0;
}

.rt-privacy strong {
    color: var(--fg);
    font-weight: 600;
}

.rt-privacy a {
    color: var(--cyan);
    text-decoration: none;
}

.rt-privacy a:hover {
    text-decoration: underline;
}

/* ── Generic modal overlay + box ────────────────────────────────────────── */
/* Used by EventSetup, ScoringGrid, and other admin pages that need a
   lightweight modal. Centered card on a dimmed backdrop. */

.rt-modal-overlay,
.pa-comment-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 1050;
    display: flex;
    align-items: center;
    justify-content: center;
}

.rt-modal-box,
.pa-comment-box {
    background: var(--bg-surface);
    color: var(--fg);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 1.25rem 1.5rem;
    min-width: 22rem;
    max-width: 36rem;
    box-shadow: var(--shadow-2);
}

.rt-modal-box h5,
.pa-comment-box h5 {
    font-family: var(--font-display);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--fg);
}

/* ── Right-click context menu ───────────────────────────────────────────── */
/* Used by the scoring grid (`wwwroot/js/scoring-grid.js`); appended to
   document.body so the CSS lives at the root, not in a component scope.
   Reference: docs/rallytrack-mockups.html lines 968–1001. */

.context-menu {
    position: absolute;
    z-index: 9999;
    background: var(--bg-elevated);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-2);
    min-width: 240px;
    padding: var(--s-2) 0;
    font-family: var(--font-body);
    font-size: 13px;
    color: var(--fg);
}

.context-menu .header {
    padding: var(--s-2) var(--s-4);
    color: var(--fg-muted);
    font-family: var(--font-mono);
    font-size: 11px;
    border-bottom: 1px solid var(--line);
    margin-bottom: var(--s-2);
}

.context-menu .header:not(:first-child) {
    margin-top: var(--s-2);
    border-top: 1px solid var(--line);
    border-bottom: none;
}

.context-menu .item {
    padding: var(--s-2) var(--s-4);
    color: var(--fg);
    cursor: pointer;
    user-select: none;
}

.context-menu .item:hover {
    background: var(--bg-elevated-2);
}

.context-menu .item.disabled {
    color: var(--fg-faint);
    cursor: not-allowed;
}

.context-menu .item.disabled:hover {
    background: transparent;
}

.context-menu .divider {
    height: 1px;
    background: var(--line);
    margin: var(--s-2) 0;
}

/* ── Event poster uploader (admin EventSetup) ────────────────────────── */

.poster-uploader {
    background: var(--bg-surface);
    border: 1px dashed var(--line-strong);
    border-radius: var(--r-md);
    padding: var(--s-4);
    display: flex;
    gap: var(--s-4);
    align-items: flex-start;
}

.poster-uploader .thumb {
    width: 120px;
    height: 160px;
    background: var(--bg-base);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--fg-faint);
    font-family: var(--font-mono);
    font-size: 11px;
    flex-shrink: 0;
    overflow: hidden;
}

.poster-uploader .thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.poster-uploader .info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--s-2);
}

.poster-uploader .info h4 {
    margin: 0;
    font-family: var(--font-display);
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--fg);
}

.poster-uploader .info p {
    margin: 0;
    color: var(--fg-muted);
    font-size: 12px;
}

.poster-uploader .info .actions {
    display: flex;
    gap: var(--s-2);
    margin-top: var(--s-2);
}

/* ── Public event page: two-column layout with optional poster ─────────── */

.event-content-row {
    display: grid;
    grid-template-columns: 1fr 280px;
    gap: var(--s-6);
    margin-top: var(--s-5);
}

.event-content-row .poster {
    /* No fixed aspect-ratio — natural image dimensions drive the height.
       Letterbox background visible when image doesn't fill container width. */
    background: var(--bg-surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    overflow: hidden;
    align-self: flex-start;
}

.event-content-row .poster img {
    width: 100%;
    height: auto;
    object-fit: contain;
    display: block;
}

@media (max-width: 720px) {
    .event-content-row {
        grid-template-columns: 1fr;
    }

    .event-content-row .poster {
        max-width: 320px;
        margin: 0 auto;
    }
}

/* Live indicator dot — canonical utility class per §5.16 / §10.2. Every
   "this is live now" indicator across the chrome + public surfaces uses
   .live-dot so the visual language stays consistent: Map tab "Live Map"
   indicator, Results button when event is Live, landing-page CTA when
   event is Live, chrome countdown when ticked over to "Live now", and
   the hero card's Live status pill on the landing page. v2.13.0 PR 7
   removed the bespoke .rt-live-dot, .event-status .dot, and
   .chrome-countdown .time.live::before variants in favour of this one. */
.live-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--rally-red);
    animation: rt-pulse 1.4s ease-out infinite;
    vertical-align: middle;
}

@keyframes rt-pulse {
    /* Start at solid red glow tight to the dot, expand outward to a wider
       fully-transparent ring. Two-stop curve (no 70% breakpoint) keeps the
       ring continuously visible across the whole 1.4s cycle — the prior
       three-stop version left the ring invisible for the back half of the
       loop, which read as "static dot" in the chrome at a glance. Starting
       alpha boosted from 0.18 to 0.65 for clearer signal in the dark
       chrome. */
    0%   { box-shadow: 0 0 0 0 rgba(225, 35, 44, 0.65); }
    100% { box-shadow: 0 0 0 14px rgba(225, 35, 44, 0); }
}
