@import '_content/Microsoft.AspNetCore.Components.QuickGrid/Microsoft.AspNetCore.Components.QuickGrid.boiwgh0w5b.bundle.scp.css';

/* /Charts/AreaLineChart.razor.rz.scp.css */
.area-line-chart[b-iic91rah10] {
    min-width: 0;
}

/* Containing block for the end dot, sized to the plot and nothing else. The dot's `top` is a percentage,
   so anything else inside this box (the readout, notably) would silently rescale where the dot lands. */
.area-line-chart-frame[b-iic91rah10] {
    position: relative;
    line-height: 0;
}

/* Height is a custom property so a host that gives the chart a whole panel (rather than one row of small
   multiples) can make it taller without fighting this rule's specificity. */
.area-line-chart-plot[b-iic91rah10] {
    display: block;
    width: 100%;
    height: var(--area-line-chart-height, 56px);
    overflow: visible;
}

/* The area is a wash, never a saturated block — the line carries the shape, the fill only groups it. */
.area-line-chart-wash[b-iic91rah10] {
    opacity: 0.1;
}

/* The end marker: an HTML dot laid over the plot, so it stays a true circle however far the SVG beneath
   it is stretched. The 2px ring in the surface colour keeps it legible where it sits on the line. */
/* The negative margin must be half the BORDER box, not half the 8px dot: the 2px surface ring adds to the
   rendered size, so pulling back by 4px leaves the dot sitting 2px below and right of the line's end. */
.area-line-chart-dot[b-iic91rah10] {
    position: absolute;
    width: 8px;
    height: 8px;
    margin: -6px 0 0 -6px;
    border-radius: 50%;
    border: 2px solid var(--chart-surface);
    box-sizing: content-box;
    pointer-events: none;
}

.area-line-chart-hit[b-iic91rah10] {
    fill: transparent;
    cursor: crosshair;
}

/* /Charts/ColumnChart.razor.rz.scp.css */
.column-chart[b-sxv7lxr2xg] {
    min-width: 0;
}

/* Uniform scaling (no preserveAspectRatio override) keeps the rounded caps circular, so the box's height
   follows its width rather than being pinned in pixels. */
.column-chart-plot[b-sxv7lxr2xg] {
    display: block;
    width: 100%;
    height: auto;
}

.column-chart-frame[b-sxv7lxr2xg] {
    position: relative;
    line-height: 0;
}

/* The bars paint over the hit targets, so they must not take the pointer themselves — otherwise moving
   onto a bar fires mouseleave on the slot beneath it and the chip flickers out over its own column. */
.column-chart-bar[b-sxv7lxr2xg] {
    pointer-events: none;
}

.column-chart-hit[b-sxv7lxr2xg] {
    fill: transparent;
    cursor: crosshair;
}

/* One cell per column, laid on the same track widths as the bars above, so each caption stays under its
   own mark. Empty cells hold the slot open where a caption was skipped for density. */
.column-chart-ticks[b-sxv7lxr2xg] {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    margin-top: 5px;
    font-size: 11px;
    font-weight: 600;
    color: #898781;
    text-align: center;
}
/* /Charts/SparklineChart.razor.rz.scp.css */
.sparkline-chart[b-s3zyn8azz5] {
    display: block;
    width: 100%;
    height: 24px;
    overflow: visible;
}
/* /Components/AdminDashboard/AdminDashboardGrowthTab.razor.rz.scp.css */
/* Small multiples: a fixed key column, then each measure's plot, so every series lines up on the same
   month columns and the shared axis below reads for all three. */
.growth-panel[b-z4bkcepxz7] {
    background: #fff;
    border: 1px solid rgba(11, 11, 11, 0.1);
    border-radius: 14px;
    padding: 20px 22px;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.045);
}

/* The plots carry no text beneath them — the hover value floats beside its dot — so the rows need their
   own separation. */
.growth-row[b-z4bkcepxz7] {
    display: grid;
    grid-template-columns: 150px minmax(0, 1fr);
    align-items: center;
    gap: 14px;
    margin-bottom: 14px;
}

.growth-key[b-z4bkcepxz7] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: baseline;
    column-gap: 7px;
    min-width: 0;
}

.growth-swatch[b-z4bkcepxz7] {
    width: 9px;
    height: 9px;
    border-radius: 2px;
    align-self: center;
}

.growth-name[b-z4bkcepxz7] {
    font-size: 12.5px;
    font-weight: 700;
    color: #52514e;
}

.growth-latest[b-z4bkcepxz7] {
    grid-column: 2;
    font-size: 17px;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: #0b0b0b;
}

.growth-period[b-z4bkcepxz7] {
    grid-column: 2;
    font-size: 11px;
    font-weight: 600;
    color: #898781;
}

.growth-axis[b-z4bkcepxz7] {
    display: grid;
    grid-template-columns: 150px minmax(0, 1fr);
    gap: 14px;
    margin-top: 2px;
}

.growth-ticks[b-z4bkcepxz7] {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    font-weight: 600;
    color: #898781;
}

@media (max-width: 640px) {
    .growth-row[b-z4bkcepxz7],
    .growth-axis[b-z4bkcepxz7] {
        grid-template-columns: minmax(0, 1fr);
        gap: 4px;
    }

    .growth-key[b-z4bkcepxz7] {
        grid-template-columns: auto auto minmax(0, 1fr);
        column-gap: 8px;
    }

    .growth-latest[b-z4bkcepxz7],
    .growth-period[b-z4bkcepxz7] {
        grid-column: auto;
    }
}
/* /Components/Court.razor.rz.scp.css */
/* ---------------------------------------------------------------------------
   Court box — pure-CSS top-down beach volleyball court.
   All colors are CSS custom properties; override .court-box from the outside
   (e.g. via a theme class or inline style) to repurpose the visual for other
   contexts (e.g. tournament categories, side-by-side allocations).
   --------------------------------------------------------------------------- */
.court-box[b-29k6kfe2x4] {
    /* configurable surface */
    --court-sand-1:    #f6dfa8;
    --court-sand-2:    #e7c980;
    --court-line:      #ffffff;
    --court-line-width: 2px;
    --court-net:       #ffffff;
    --court-net-shadow: rgba(0, 0, 0, 0.18);
    --court-name-bg:   rgba(255, 255, 255, 0.92);
    --court-name-fg:   #0f2a36;
    --court-radius:    12px;
    --court-shadow:    0 4px 12px rgba(15, 42, 54, 0.10);
    --court-shadow-hover: 0 8px 20px rgba(15, 42, 54, 0.18);

    position: relative;
    aspect-ratio: 2 / 1;
    border-radius: var(--court-radius);
    background:
        radial-gradient(ellipse at 20% 30%, rgba(255, 255, 255, 0.18), transparent 40%),
        radial-gradient(ellipse at 80% 70%, rgba(255, 255, 255, 0.10), transparent 50%),
        linear-gradient(135deg, var(--court-sand-1) 0%, var(--court-sand-2) 100%);
    box-shadow:
        inset 0 0 0 var(--court-line-width) var(--court-line),
        var(--court-shadow);
    overflow: hidden;
    transition: box-shadow 0.15s;
}

.court-box:hover[b-29k6kfe2x4] {
    box-shadow:
        inset 0 0 0 var(--court-line-width) var(--court-line),
        var(--court-shadow-hover);
}

.court-box:focus-within[b-29k6kfe2x4] {
    box-shadow:
        inset 0 0 0 var(--court-line-width) var(--court-line),
        0 0 0 3px rgba(14, 165, 183, 0.3),
        var(--court-shadow-hover);
}

/* Center net — dashed strip down the middle */
.court-box[b-29k6kfe2x4]::before {
    content: "";
    position: absolute;
    top: 8%;
    bottom: 8%;
    left: 50%;
    width: 4px;
    transform: translateX(-50%);
    background: repeating-linear-gradient(
        to bottom,
        var(--court-net) 0 4px,
        transparent 4px 8px
    );
    box-shadow: 0 0 0 1px var(--court-net-shadow);
    border-radius: 2px;
    pointer-events: none;
}

.court-remove[b-29k6kfe2x4] {
    position: absolute;
    top: 5px;
    right: 5px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.85);
    color: #5b7280;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(4px);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    transition: background-color 0.12s, color 0.12s;
    z-index: 2;
}

.court-remove:hover[b-29k6kfe2x4] {
    background: #ffe5ec;
    color: #e50350;
}

.court-name-strip[b-29k6kfe2x4] {
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 6px;
    z-index: 1;
    display: flex;
    align-items: stretch;
    gap: 4px;
}

/* Localized "Court" word shown as a fixed chip; the editable/read-only value carries only the bare number. */
.court-name-prefix[b-29k6kfe2x4] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    background: var(--court-name-bg);
    color: var(--court-name-fg);
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.court-name-value[b-29k6kfe2x4] {
    flex: 1 1 auto;
    min-width: 0;
}

/* Shared pill look applied to both the InputEdit display chip and its
   textarea state, plus the read-only fallback. The display state shows the
   name as a label; clicking turns it into the textarea. */
.court-name-readonly[b-29k6kfe2x4],
.court-name-strip[b-29k6kfe2x4]  .text-input-display,
.court-name-strip[b-29k6kfe2x4]  .text-input-textarea {
    display: block;
    width: 100%;
    box-sizing: border-box;
    background: var(--court-name-bg);
    color: var(--court-name-fg);
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-radius: 6px;
    padding: 4px 8px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.2;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.court-name-strip[b-29k6kfe2x4]  .text-input-display {
    cursor: text;
    transition: background 0.12s, border-color 0.12s;
}

.court-name-strip[b-29k6kfe2x4]  .text-input-display:hover {
    background: #ffffff;
}

.court-name-strip[b-29k6kfe2x4]  .text-input-textarea {
    outline: none;
    resize: none;
    overflow: hidden;
    transition: border-color 0.12s, box-shadow 0.12s;
}

.court-name-strip[b-29k6kfe2x4]  .text-input-textarea:focus {
    border-color: rgba(14, 165, 183, 0.7);
    box-shadow: 0 0 0 3px rgba(14, 165, 183, 0.25);
}

.court-name-strip[b-29k6kfe2x4]  .text-input-textarea::placeholder {
    color: #8a96a3;
    font-style: normal;
    font-weight: 500;
}

.court-name-strip[b-29k6kfe2x4]  .text-input-edit-icon {
    color: #8a96a3;
}

.court-name-strip[b-29k6kfe2x4]  .text-input-display:hover .text-input-edit-icon {
    color: #0f2a36;
}

.court-name-strip[b-29k6kfe2x4]  .text-input-value {
    padding-right: 14px; /* room for the pencil icon */
}

.court-name-strip[b-29k6kfe2x4]  .text-input-placeholder {
    color: #8a96a3;
    font-style: normal;
    font-weight: 500;
}
/* /Components/LoggingErrorBoundary.razor.rz.scp.css */
.logging-error-boundary[b-dn623vfi9z] {
    background: #b32121;
    color: white;
    padding: 1rem;
    border-radius: 0.25rem;
}

.logging-error-boundary code[b-dn623vfi9z] {
    color: white;
    font-weight: bold;
}
/* /Components/MatchResultDialog.razor.rz.scp.css */
.mr[b-4wciqunmhc] {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

/* ── Always-editable sets grid ─────────────────────────────────────────────── */
.mr-grid[b-4wciqunmhc] {
    display: grid;
    gap: 8px;
    align-items: center;
}

.mr-h[b-4wciqunmhc] {
    font-size: 10px;
    font-weight: 800;
    color: #5b7280;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    text-align: center;
}

.mr-h-team[b-4wciqunmhc] {
    text-align: left;
}

.mr-h-derived[b-4wciqunmhc] {
    color: var(--brand-primary-dark);
}

.mr-h-target[b-4wciqunmhc] {
    display: block;
    font-size: 9px;
    font-weight: 800;
    color: var(--brand-primary-dark);
    margin-top: 1px;
}

.mr-team[b-4wciqunmhc] {
    display: flex;
    align-items: center;
    min-width: 0;
}

/* Stacked full player names, one per line. */
.mr-names[b-4wciqunmhc] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.mr-name[b-4wciqunmhc] {
    font-size: 14px;
    font-weight: 800;
    color: #0f2a36;
    line-height: 1.15;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Dispute banner ─────────────────────────────────────────────────────────
   Sits inside the shared <Banner>, which supplies the amber wash, border and dispute icon and keeps that
   icon on the caption's line; this only stacks the two lines beside it. */
.mr-dispute[b-4wciqunmhc] {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.mr-dispute-who[b-4wciqunmhc] {
    font-size: 12.5px;
    font-weight: 800;
}

/* The player's own words, set apart from the caption above so it reads as a quotation rather than more
   app copy. <q> supplies the locale's quotation marks. */
.mr-dispute-note[b-4wciqunmhc] {
    font-size: 12.5px;
    font-weight: 600;
    font-style: italic;
    line-height: 1.35;
    /* Free text from a player: keep long words and pasted strings inside the dialog. */
    overflow-wrap: anywhere;
}

.mr-loading[b-4wciqunmhc] {
    display: grid;
    place-items: center;
    min-height: 160px;
}

.mr-cell[b-4wciqunmhc] {
    display: grid;
    place-items: center;
}

.mr-help[b-4wciqunmhc] {
    margin: 0;
    font-size: 11.5px;
    font-weight: 700;
    color: #5b7280;
}

/* ── Footer (white-dialog button styling, mirrors the dialog container) ─────── */
.mr-foot[b-4wciqunmhc] {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    padding-top: 6px;
    border-top: 1px solid #eef3f4;
}

.mr-wo-btn[b-4wciqunmhc] {
    margin-right: auto;
}

.mr-wo-ask[b-4wciqunmhc] {
    font-size: 12px;
    font-weight: 800;
    color: #5b7280;
    margin-right: auto;
}

/* Button styling now comes from the shared <AppButton> (.app-btn) primitive. */
/* /Components/MatchResultDisputeDialog.razor.rz.scp.css */
/* Dialog body: a short explanation of what disputing does, then the note field. */
.mrd[b-vn3rjd61fh] {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.mrd-intro[b-vn3rjd61fh] {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: #5b7280;
}
/* /Components/MoveScheduleStartTimeDialog.razor.rz.scp.css */
.mst[b-ghnm8as5ta] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/PoolRoundFormat.razor.rz.scp.css */
/* Live pool standings tables shown inside the pools dialog. Qualifier rows tint to the brand-teal; a dashed
   cut-line marks the qualification boundary. Brand tokens (--brand-primary etc.) come from app.css :root. */
.rpf-loading[b-gxa9y9541k] {
    display: flex;
    justify-content: center;
    padding: 32px 0;
}

.rpf-empty[b-gxa9y9541k] {
    margin: 0;
    padding: 24px 4px;
    text-align: center;
    color: #5b7280;
    font-size: 14px;
}

/* The host scroll region is a column flex; claim its full height so the grid below can spread
   the group tables over the whole visible area rather than hugging the top. */
.rpf[b-gxa9y9541k] {
    flex: 1;
    display: flex;
    flex-direction: column;
}

/* Balanced grid over the whole visible region: the component computes a near-square,
   landscape-biased column count from the group count (--rpf-cols; e.g. 4 groups → 2×2,
   6 → 3×2) so no row is left lopsided like flex-wrap's 3+1. Columns share the width
   equally and leftover height is distributed evenly between the rows. --rpf-cols-md/-sm
   are the same count pre-clamped to 3/2 for viewports where fewer tables fit per row.
   --rpf-cols-portrait is the transposed, portrait-biased count (fewer columns / more
   rows, e.g. 6 groups → 2×3) applied when the viewport is taller than wide, so the
   tables fill the height instead of squishing into a wide-but-short band. */
.rpf-grid[b-gxa9y9541k] {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(var(--rpf-cols, 1), minmax(0, 1fr));
    align-content: space-evenly;
    align-items: start;
    gap: 14px 20px;
}

@media (max-width: 1459px) {
    .rpf-grid[b-gxa9y9541k] {
        grid-template-columns: repeat(var(--rpf-cols-md, 1), minmax(0, 1fr));
    }
}

@media (max-width: 1079px) {
    .rpf-grid[b-gxa9y9541k] {
        grid-template-columns: repeat(var(--rpf-cols-sm, 1), minmax(0, 1fr));
    }
}

/* Portrait (taller than wide): fewer columns, more rows — overrides the width-based
   landscape counts above regardless of width. */
@media (orientation: portrait) {
    .rpf-grid[b-gxa9y9541k] {
        grid-template-columns: repeat(var(--rpf-cols-portrait, 1), minmax(0, 1fr));
    }
}

@media (orientation: portrait) and (max-width: 1079px) {
    .rpf-grid[b-gxa9y9541k] {
        grid-template-columns: repeat(var(--rpf-cols-portrait-sm, 1), minmax(0, 1fr));
    }
}

/* Kept last so it wins in both orientations: single column on the narrowest viewports. */
@media (max-width: 739px) {
    .rpf-grid[b-gxa9y9541k] {
        grid-template-columns: minmax(0, 1fr);
    }
}

.rpf-group[b-gxa9y9541k] {
    min-width: 0;
    background: #fff;
    border: 1px solid #e7ebee;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 6px 18px rgba(10, 42, 54, 0.06);
}

.rpf-ghead[b-gxa9y9541k] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    background: #eef3f4;
    border-bottom: 1px solid #e7ebee;
}

.rpf-badge[b-gxa9y9541k] {
    width: 27px;
    height: 27px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    font-weight: 800;
    font-size: 14px;
    color: #fff;
    background: linear-gradient(150deg, var(--brand-primary-light), var(--brand-primary-dark));
}

.rpf-gtitle[b-gxa9y9541k] {
    margin: 0;
}

.rpf-table[b-gxa9y9541k] {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.rpf-table thead th[b-gxa9y9541k] {
    font-size: 9.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #5b7280;
    text-align: right;
    padding: 8px 5px 7px;
    white-space: nowrap;
}

.rpf-table thead th.rpf-l[b-gxa9y9541k] {
    text-align: left;
}

.rpf-table thead th:first-child[b-gxa9y9541k] {
    padding-left: 11px;
    text-align: center;
    width: 40px;
}

.rpf-table thead th:last-child[b-gxa9y9541k] {
    padding-right: 11px;
}

.rpf-table tbody td[b-gxa9y9541k] {
    font-size: 12px;
    padding: 5px 5px;
    border-top: 1px solid #f1f5f6;
    text-align: right;
    white-space: nowrap;
    color: #0f2a36;
}

    .rpf-table tbody td:first-child[b-gxa9y9541k] {
        padding-left: 11px;
        text-align: center;
    }

.rpf-table tbody td:last-child[b-gxa9y9541k] {
    padding-right: 11px;
}

.rpf-rank[b-gxa9y9541k] {
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 800;
    background: #eef1f3;
    color: #5b7280;
}

.rpf-team[b-gxa9y9541k] {
    text-align: left !important;
    white-space: normal;
}

/* The team column is now just the player stack, left-aligned. */
.rpf-teamline[b-gxa9y9541k] {
    display: flex;
    align-items: flex-start;
    gap: 6px;
}

/* The rank column stacks the per-group rank over the overall-placement pill (when shown), centred. */
.rpf-rankcell[b-gxa9y9541k] {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

/* Final overall placement across all pools — a small pill under the per-group rank, shown only once every pool
   game is in (see PoolTeamStandingDomainModel.OverallRank). Its darker fill keeps it from reading as the same
   number as the light per-group "#" rank above it. */
.rpf-overall[b-gxa9y9541k] {
    flex: none;
    padding: 1px 6px;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    background: #0f2a36;
    color: #fff;
}

/* Players stack vertically (one PlayerLabel per line) rather than sharing a single horizontal row, so the
   full, unabbreviated names fit the narrow team column and use the available vertical space. */
.rpf-players[b-gxa9y9541k] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    font-weight: 700;
    font-size: 12.5px;
    line-height: 1.25;
}

/* Games column: bold total, then a lighter (W:L:D) breakdown so the played count reads first. */
.rpf-gp-total[b-gxa9y9541k] {
    font-weight: 700;
}

.rpf-wld[b-gxa9y9541k] {
    margin-left: 4px;
    color: #5b7280;
    font-size: 11px;
    font-weight: 100;
}

.rpf-sets[b-gxa9y9541k] {
    font-weight: 700;
    color: #5b7280;
    font-variant-numeric: tabular-nums;
}

.rpf-score[b-gxa9y9541k] {
    font-weight: 700;
}

.rpf-pts[b-gxa9y9541k] {
    font-weight: 800;
    font-size: 13.5px;
    color: var(--brand-primary-dark);
}

.rpf-table tbody tr.rpf-q[b-gxa9y9541k] {
    background: #e8f7f0;
}

.rpf-table tbody tr.rpf-q .rpf-rank[b-gxa9y9541k] {
    background: #9fe1cb;
    color: #0f6e56;
}

.rpf-table tbody tr.rpf-q td:first-child[b-gxa9y9541k] {
    box-shadow: inset 3px 0 0 #9fe1cb;
}

.rpf-table tbody tr.rpf-cut td[b-gxa9y9541k] {
    border-top: 2px dashed #c8d0d4;
}

/* The viewer's own team on the player-today page: a brand edge plus bolder names, so "which row am I"
   reads at a glance. Wins over the advancement edge above, which is why it follows it. */
.rpf-table tbody tr.rpf-me td:first-child[b-gxa9y9541k] {
    box-shadow: inset 3px 0 0 var(--brand-primary);
}

.rpf-table tbody tr.rpf-me .rpf-players[b-gxa9y9541k] {
    font-weight: 800;
}
/* /Components/RoundRobinRoundFormat.razor.rz.scp.css */
/* Live round-robin standings: one table over the whole field, centred in the host scroll region and capped so
   the rows stay readable on a wide screen rather than stretching edge to edge. Brand tokens (--brand-primary
   etc.) come from app.css :root. */
.rrf-loading[b-5l0w48y78v] {
    display: flex;
    justify-content: center;
    padding: 32px 0;
}

.rrf-empty[b-5l0w48y78v] {
    margin: 0;
    padding: 24px 4px;
    text-align: center;
    color: #5b7280;
    font-size: 14px;
}

/* The host (.app-scroll-region.catbar-content) is a height-constrained column flex, so this card must opt out
   of flex shrinking: as a shrinkable item it would be squeezed below the table's natural height, and since the
   host only scrolls once its content actually overflows, the lower rows would be cut off with no way to reach
   them. `flex: none` keeps the full table height and hands the scrolling to the host.
   `width: 100%` is likewise load-bearing — the auto side margins that centre the card would otherwise size it
   to fit-content, leaving it far narrower than the max-width cap. Corner rounding is applied to the edge cells
   rather than via `overflow: hidden`, which would clip the rank tooltip where it escapes the card. */
.rrf[b-5l0w48y78v] {
    flex: none;
    width: 100%;
    max-width: 760px;
    margin: 0 auto;
    background: #fff;
    border: 1px solid #e7ebee;
    border-radius: 12px;
    box-shadow: 0 6px 18px rgba(10, 42, 54, 0.06);
}

.rrf-table[b-5l0w48y78v] {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.rrf-table thead th[b-5l0w48y78v] {
    font-size: 9.5px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #5b7280;
    text-align: right;
    padding: 10px 6px 9px;
    white-space: nowrap;
    background: #eef3f4;
    border-bottom: 1px solid #e7ebee;
}

.rrf-table thead th.rrf-l[b-5l0w48y78v] {
    text-align: left;
}

.rrf-table thead th:first-child[b-5l0w48y78v] {
    padding-left: 12px;
    text-align: center;
    width: 58px;
    border-top-left-radius: 12px;
}

/* Keeps the "#" and its info glyph on one baseline in the narrow rank column. */
.rrf-rankhead[b-5l0w48y78v] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.rrf-table thead th:last-child[b-5l0w48y78v] {
    padding-right: 12px;
    border-top-right-radius: 12px;
}

.rrf-table tbody td[b-5l0w48y78v] {
    font-size: 12.5px;
    padding: 7px 6px;
    border-top: 1px solid #f1f5f6;
    text-align: right;
    white-space: nowrap;
    color: #0f2a36;
}

.rrf-table tbody td:first-child[b-5l0w48y78v] {
    padding-left: 12px;
    text-align: center;
}

.rrf-table tbody td:last-child[b-5l0w48y78v] {
    padding-right: 12px;
}

/* Bottom corners of the card, rounded on the last row's edge cells (see the .rrf note on why the card can't
   simply clip its overflow). */
.rrf-table tbody tr:last-child td:first-child[b-5l0w48y78v] {
    border-bottom-left-radius: 12px;
}

.rrf-table tbody tr:last-child td:last-child[b-5l0w48y78v] {
    border-bottom-right-radius: 12px;
}

.rrf-rank[b-5l0w48y78v] {
    display: inline-grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    font-size: 11.5px;
    font-weight: 800;
    background: #eef1f3;
    color: #5b7280;
}

/* The per-column cell rules below are written as `td.<class>` on purpose: the generic
   `.rrf-table tbody td` rule above carries two type selectors, so a bare single-class rule would lose to it
   and silently do nothing (its colour / white-space would never apply). */
.rrf-table tbody td.rrf-team[b-5l0w48y78v] {
    text-align: left;
    white-space: normal;
}

/* Players stack vertically (one PlayerLabel per line) rather than sharing a single horizontal row, so the
   full, unabbreviated names fit the team column and use the available vertical space. */
.rrf-players[b-5l0w48y78v] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    font-weight: 700;
    font-size: 12.5px;
    line-height: 1.25;
}

/* Games column: bold total, then a lighter (W:L:D) breakdown so the played count reads first. */
.rrf-gp-total[b-5l0w48y78v] {
    font-weight: 700;
}

.rrf-wld[b-5l0w48y78v] {
    margin-left: 4px;
    color: #5b7280;
    font-size: 11px;
    font-weight: 100;
}

.rrf-table tbody td.rrf-sets[b-5l0w48y78v] {
    font-weight: 700;
    color: #5b7280;
    font-variant-numeric: tabular-nums;
}

.rrf-table tbody td.rrf-score[b-5l0w48y78v] {
    font-weight: 700;
}

/* The points column is the headline number of the table — the brand accent sets it apart from the
   supporting stats. */
.rrf-table tbody td.rrf-pts[b-5l0w48y78v] {
    font-weight: 800;
    font-size: 13.5px;
    color: var(--brand-primary-dark);
}
/* /Components/ScheduleReorganizer.razor.rz.scp.css */
/* Reorganiser styling — the per-court group strips (rendered into the timeline's court header via the
   CourtGroups fragment) and the seed-assignment side panel. These elements are authored in
   ScheduleReorganizer.razor, so they carry this component's scope attribute and these rules match them
   wherever the host renders them (the Schedule staging page or the Live page's reorganise mode). The
   court-label layout overrides (rotated spine, --ts-courtw width) stay in each host page's scoped CSS,
   anchored on that page's timeline element. */

/* The groups area sits to the right of the spine: [group strips][side column]. The side column holds the
   sequencing toggle (top) above the add/remove actions, so the strips stretch the full lane height. */
.ts-court-groups[b-7mieg78gk1] {
    flex: 1;
    display: flex;
    align-items: stretch;
    gap: 8px;
    min-width: 0;
    margin-top: 0;
}

/* Right-hand column: the horizontal sequencing toggle sits at the top; the add action is absolutely
   centred against the FULL lane height (see .ts-gactions) so the + keeps the same vertical position
   whether or not the toggle is present. Sits to the right of the group strips. */
.ts-gside[b-7mieg78gk1] {
    flex: none;
    position: relative;
    /* Pin to the right edge: when the group strips are present they already consume the free space
       (flex: 1) so this is a no-op, but with no groups the strips aren't rendered — the auto margin then
       keeps this column (and its + button) anchored right instead of collapsing to the far left. */
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

/* The horizontal run of vertical group strips. Sized to its content (flex: none): it must NOT grow —
   growing would leave an empty band behind the last strip — and must NOT shrink, or the fixed-width
   strips would overflow rightward and be painted over by the side toggle column. The side column is
   pinned to the lane's right edge by its own margin-left: auto, so the only space after the strips is
   the delete-foot clearance. The court width (--ts-courtw, see CourtColumnWidthPx) is sized to fit. */
.ts-gstrips[b-7mieg78gk1] {
    flex: none;
    display: flex;
    align-items: stretch;
    gap: 5px;
}

/* One group panel = badge over rotated category. The per-strip trashcan sticks OUT past the
   bottom-right corner (an L-foot), so overflow stays visible and the rotated label keeps its full
   height — the delete control never eats into the label's space. */
.ts-gstrip[b-7mieg78gk1] {
    position: relative;
    flex: none;
    display: flex;
    align-items: stretch;
    border: 1px solid var(--border-color, #e2e6ea);
    border-radius: 9px 9px 0 9px;
    background: #fff;
    overflow: visible;
    /* The whole strip body is a click target (opens the group's seed-ordering panel). */
    cursor: pointer;
    transition: border-color 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
}

/* Primary hover ring, mirroring the match boxes — signals the pill opens the same seed-ordering panel. */
.ts-gstrip:hover[b-7mieg78gk1] {
    border-color: var(--brand-primary, #0a6f7d);
    box-shadow: 0 0 0 1px var(--brand-primary, #0a6f7d), 0 4px 12px rgba(14, 165, 183, 0.18);
}

/* …and the delete foot joins that primary ring too (border + matching shadow), but NOT while the foot
   itself is hovered (that case turns everything red below), so body + foot read as one outlined target.
   The foot's ring skips its left side (the seam shared with the body) so the L-outline has no inner line. */
.ts-gstrip:hover:not(:has(.ts-gdel:hover)) .ts-gdel:not(:disabled)[b-7mieg78gk1] {
    border-color: var(--brand-primary, #0a6f7d);
    box-shadow: 1px 0 0 0 var(--brand-primary, #0a6f7d), 0 -1px 0 0 var(--brand-primary, #0a6f7d), 0 1px 0 0 var(--brand-primary, #0a6f7d), 0 4px 12px rgba(14, 165, 183, 0.18);
}

/* Hovering the delete foot turns the WHOLE pill red — body + foot share the rose fill, border and ring —
   so it's clear the action removes the entire group, not just the foot. The foot's ring again skips its
   left (seam) side so body + foot read as one continuous red outline. */
.ts-gstrip:has(.ts-gdel:hover:not(:disabled))[b-7mieg78gk1] {
    border-color: var(--seed-rose, #b1395f);
    background: #fdecf1;
    box-shadow: 0 0 0 1px var(--seed-rose, #b1395f), 0 4px 12px rgba(177, 57, 95, 0.18);
}

.ts-gstrip:has(.ts-gdel:hover:not(:disabled)) .ts-gdel[b-7mieg78gk1] {
    box-shadow: 1px 0 0 0 var(--seed-rose, #b1395f), 0 -1px 0 0 var(--seed-rose, #b1395f), 0 1px 0 0 var(--seed-rose, #b1395f), 0 4px 12px rgba(177, 57, 95, 0.18);
}

/* A single swap control between two adjacent strips, exchanging the play order of the pair (replacing
   the old per-strip ‹ and › arrows). To save horizontal space it is just the icon inline — no border,
   no background, a slim 14px column. On hover/focus the ::before grows into a bordered, filled chip
   that spills over the two pills it will swap, signalling the pair (isolate + raised z-index let it
   paint above the neighbouring strips). */
.ts-gswap[b-7mieg78gk1] {
    flex: none;
    align-self: center;
    position: relative;
    isolation: isolate;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 22px;
    padding: 0;
    border: 0;
    background: transparent;
    color: #9fb0ba;
    cursor: pointer;
    font-size: 11px;
}

/* Keep the arrows above the hover chip. */
.ts-gswap > i[b-7mieg78gk1] {
    position: relative;
    z-index: 1;
}

/* The expand-on-hover chip: centred on the slim button, transparent (invisible) at rest so only the
   icon shows; on hover it widens past the gap to overlap both neighbouring strips. */
.ts-gswap[b-7mieg78gk1]::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 100%;
    height: 100%;
    transform: translate(-50%, -50%);
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    transition: width 0.12s ease, height 0.12s ease, background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}

.ts-gswap:hover:not(:disabled)[b-7mieg78gk1],
.ts-gswap:focus-visible:not(:disabled)[b-7mieg78gk1] {
    color: var(--brand-primary, #0a6f7d);
    z-index: 3;
    outline: none;
}

.ts-gswap:hover:not(:disabled)[b-7mieg78gk1]::before,
.ts-gswap:focus-visible:not(:disabled)[b-7mieg78gk1]::before {
    width: 40px;
    height: 40px;
    border-color: var(--brand-primary, #0a6f7d);
    background: #ffffff85;
    box-shadow: 0 2px 8px rgba(10, 42, 54, 0.18);
}

.ts-gswap:disabled[b-7mieg78gk1] {
    color: #d8e0e4;
    cursor: default;
}

.ts-gcenter[b-7mieg78gk1] {
    flex: none;
    width: 24px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 5px 1px 6px;
}

.ts-group-badge[b-7mieg78gk1] {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--brand-primary, #0a6f7d);
    color: #fff;
    font-size: 11px;
    font-weight: 800;
}

/* Category reads bottom → top, matching the match cards' category spine (.tl-spine-txt) direction;
   ellipsises if it runs past the lane height (full text in title). */
.ts-gcat[b-7mieg78gk1] {
    flex: 1;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    color: #5b7280;
    font-size: 10px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Per-strip trashcan, styled as a "foot" so the pill's own background stretches out at the bottom-right
   to wrap the icon — the strip + foot read as one continuous L shape. The foot shares the pill's white
   fill and border but drops its left border and overlaps the pill's right edge by ~2px, so the seam
   between body and foot disappears (the foot's top border becomes the L's inner corner). The rotated
   label keeps its full height — the foot only extends the bottom. Muted at rest; tints rose on hover.
   Stops click propagation in markup so it deletes the one group instead of opening the seed panel. */
.ts-gdel[b-7mieg78gk1] {
    position: absolute;
    left: calc(100%);
    bottom: -1px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 24px;
    padding: 0;
    border: 1px solid var(--border-color, #e2e6ea);
    border-left: 0;
    border-radius: 0 8px 8px 0;
    background: #fff;
    color: #b6c4cc;
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    z-index: 2;
}

.ts-gdel:hover:not(:disabled)[b-7mieg78gk1] {
    background: #fdecf1;
    border-color: var(--seed-rose, #b1395f);
    color: var(--seed-rose, #b1395f);
}

.ts-gdel:disabled[b-7mieg78gk1] {
    color: #dde3e6;
    cursor: default;
}

/* Trailing actions inside the side column: just the + add button now (removal moved onto each strip).
   Absolutely centred against the full lane height and pinned to the right edge, so the + lands in the
   same spot regardless of whether the sequencing toggle occupies the top of the column. */
.ts-gactions[b-7mieg78gk1] {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.ts-group-add-wrap[b-7mieg78gk1] {
    position: relative;
    display: inline-flex;
}

.ts-group-add[b-7mieg78gk1] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 1px dashed #b6c4cc;
    border-radius: 50%;
    background: #fff;
    color: #5b7280;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}

.ts-group-add:hover:not(:disabled)[b-7mieg78gk1] {
    border-color: var(--brand-primary, #0a6f7d);
    color: var(--brand-primary, #0a6f7d);
}

.ts-group-add-backdrop[b-7mieg78gk1] {
    position: fixed;
    inset: 0;
    z-index: 11;
    border: 0;
    padding: 0;
    background: transparent;
    cursor: default;
}

.ts-group-add-menu[b-7mieg78gk1] {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 12;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 90px;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(10, 42, 54, 0.18), 0 0 0 1px rgba(10, 42, 54, 0.06);
    padding: 4px;
}

.ts-group-add-item[b-7mieg78gk1] {
    text-align: left;
    white-space: nowrap;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: #0f2a36;
    font-size: 11px;
    font-weight: 700;
    padding: 4px 8px;
    cursor: pointer;
}

.ts-group-add-item:hover[b-7mieg78gk1] {
    background: #eef3f4;
}

/* Per-court sequencing: icon-only buttons laid out horizontally (list-order = Sequential, repeat =
   Round-robin), sitting at the top of the court lane's right-hand column when more than one group shares
   the court. The full description lives in each button's title. */
.ts-seq[b-7mieg78gk1] {
    flex: none;
    display: flex;
    flex-direction: row;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--border-color, #e2e6ea);
    border-radius: 7px;
    background: #f1f5f6;
}

.ts-seq-btn[b-7mieg78gk1] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: #5b7280;
    cursor: pointer;
}

.ts-seq-btn i[b-7mieg78gk1] {
    font-size: 13px;
}

.ts-seq-btn:hover:not(:disabled):not(.active)[b-7mieg78gk1] {
    color: #0f2a36;
}

.ts-seq-btn.active[b-7mieg78gk1] {
    background: #fff;
    color: var(--brand-primary, #0a6f7d);
    box-shadow: 0 1px 2px rgba(10, 42, 54, 0.12);
}

.ts-seq-btn:disabled[b-7mieg78gk1] {
    cursor: default;
}

/* ── Seed-assignment grid (block menu content) ──────────────────────────────
   One line per team, each line a dropdown filled in that team's seed colour showing the
   team (player) names; opening it lists the other seeds as colour swatches to swap into. */
.ts-seedgrid[b-7mieg78gk1] {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 230px;
}

.ts-seedline[b-7mieg78gk1] {
    position: relative;
}

/* The line itself is the dropdown trigger: a solid seed-colour pill with white names. */
.ts-seedline-trigger[b-7mieg78gk1] {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 10px;
    border: 0;
    border-radius: 8px;
    color: #fff;
    text-align: left;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(15, 42, 54, 0.22);
}

.ts-seedline-trigger:disabled[b-7mieg78gk1] {
    cursor: default;
    opacity: 0.7;
}

.ts-seedline-num[b-7mieg78gk1] {
    flex: none;
    min-width: 15px;
    font-size: 13px;
    font-weight: 900;
}

.ts-seedline-name[b-7mieg78gk1] {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12px;
    font-weight: 800;
}

.ts-seedline-caret[b-7mieg78gk1] {
    flex: none;
    font-size: 10px;
    opacity: 0.85;
}

/* Full-screen click-away layer behind an open line dropdown. */
.ts-seedline-backdrop[b-7mieg78gk1] {
    position: fixed;
    inset: 0;
    z-index: 12;
    border: 0;
    padding: 0;
    background: transparent;
    cursor: default;
}

/* The other seeds as a compact wrap of colour swatches — each just the number on its seed colour
   (the team currently at that seed is the swatch's hover title). */
.ts-seedline-menu[b-7mieg78gk1] {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 13;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 5px;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(10, 42, 54, 0.22), 0 0 0 1px rgba(10, 42, 54, 0.08);
}

.ts-seedline-opt[b-7mieg78gk1] {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 7px;
    color: #fff;
    font-size: 14px;
    font-weight: 900;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(15, 42, 54, 0.22);
}

.ts-seed-empty[b-7mieg78gk1] {
    font-size: 12px;
    color: #5b7280;
    padding: 4px 2px;
}

/* Footer below the seed grid holding the "reset to original order" action; full-width button,
   separated from the seats above by a hairline. */
.ts-seed-footer[b-7mieg78gk1] {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid #e2e8f0;
}

.ts-seed-reset[b-7mieg78gk1] {
    width: 100%;
    justify-content: center;
}
/* /Components/SubstitutePlayerDialog.razor.rz.scp.css */
.sub[b-ot4vupgxh4] {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
    /* Enough height that the first field's autocomplete drop-down sits within the card. */
    min-height: 300px;
}

.sub-loading[b-ot4vupgxh4] {
    display: grid;
    place-items: center;
    min-height: 140px;
}

.sub-field[b-ot4vupgxh4] {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.sub-field-label[b-ot4vupgxh4] {
    font-size: 10px;
    font-weight: 800;
    color: #5b7280;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.sub-chip[b-ot4vupgxh4] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border: 1.5px solid #e7ebee;
    border-radius: 12px;
    background: #fff;
    min-width: 0;
}

.sub-chip-name[b-ot4vupgxh4] {
    font-size: 14px;
    font-weight: 800;
    color: #0f2a36;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sub-chip-remove[b-ot4vupgxh4] {
    margin-left: auto;
    border: none;
    background: transparent;
    color: #9aa6ad;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
}

.sub-chip-remove:hover[b-ot4vupgxh4] {
    color: #ef4444;
}

.sub-search-name[b-ot4vupgxh4] {
    font-size: 14px;
    font-weight: 700;
    color: #0f2a36;
}

.sub-av[b-ot4vupgxh4] {
    width: 34px;
    height: 34px;
}

.sub-av-sm[b-ot4vupgxh4] {
    width: 26px;
    height: 26px;
    font-size: 10px;
}

.sub-foot[b-ot4vupgxh4] {
    display: flex;
    gap: 10px;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    padding-top: 6px;
    border-top: 1px solid #eef3f4;
    /* Push the actions to the bottom of the (min-height) dialog card. */
    margin-top: auto;
}
/* /Components/TournamentCategoryRounds.razor.rz.scp.css */
/* Category-rounds strip docked above the live timeline. The band is a GRID, not a flex row, because every
   card — including ones pushed onto a wrapped row — must be the SAME width: a grid's column tracks are shared
   by all rows, whereas a flex row distributes its own free space independently (so a sparse wrapped row would
   stretch its cards wider). repeat(auto-fit, …) packs as many uniform columns as fit at the card floor width
   (fewest rows), then grows them in lock-step up to the card cap; so a wide strip shrinks every card BELOW the
   cap to keep them on one row, and only wraps once a card can't fit even at the floor.
   The column bounds are derived from --n (the largest round count): the spine plus n chevrons at the floor /
   cap, less the n-1 tip↔notch overlaps. The band's own width is capped (via --cols, the category count) at
   every card sitting at its cap, so once there's more room than that the band stops growing and the parent
   toolbar (justify-content:flex-end) right-aligns the packed cluster — leaving ONE gap on the left rather than
   stretching the columns apart. Below that width the 1fr columns shrink/wrap to fit.
   --cr-chv-cap / --cr-chv-floor / --cr-chv-overlap / --cr-spine-w / --cr-gap are the single source of truth
   for the chevron width bounds, the overlap, the fixed spine width, and the inter-card gap — also referenced
   by the chevron max-width and negative margin so the geometry can't drift out of sync. */
.cr-band[b-llfrc2tlrm] {
    --cr-chv-cap: 300px;
    --cr-chv-floor: 100px;
    --cr-chv-overlap: 9px;
    --cr-spine-w: 24px;
    --cr-gap: 8px;
    --cr-card-floor: calc(var(--cr-spine-w) + var(--n, 1) * var(--cr-chv-floor) - (var(--n, 1) - 1) * var(--cr-chv-overlap));
    --cr-card-cap: calc(var(--cr-spine-w) + var(--n, 1) * var(--cr-chv-cap) - (var(--n, 1) - 1) * var(--cr-chv-overlap));
    box-sizing: border-box;
    flex: 0 1 auto;
    min-width: 0;
    /* Cap the strip at all cards at their cap (then the toolbar right-aligns it); shrink to the toolbar width
       when there's less room, which is what lets the 1fr columns shrink and wrap. */
    width: calc(var(--cols, 1) * var(--cr-card-cap) + (var(--cols, 1) - 1) * var(--cr-gap));
    max-width: 100%;
    display: grid;
    /* auto-fit packs as many uniform columns as fit at the card floor, then stretches them equally (1fr) to
       fill the strip — uniform across every row. The max is 1fr, not the card cap, because a fixed max makes
       the browser pack columns at that cap (too few per row); the cap is instead enforced by the band width
       above plus the cell max-width, so the chevrons never exceed it and the surplus becomes a left gap. */
    grid-template-columns: repeat(auto-fit, minmax(var(--cr-card-floor), 1fr));
    align-items: flex-start;
    gap: var(--cr-gap);
    padding: 8px 12px;
    background: #fff;
    border-bottom: 1px solid var(--border-color, #e2e6ea);
}

.cr-cell[b-llfrc2tlrm] {
    /* A grid item that stretches to fill its (uniform) column — keeping every card the same width on every
       row — but never wider than its content cap (spine + chevrons at the cap), so once the columns stretch
       past the cap the surplus shows as grid gap rather than a hollow card. min-width:0 lets it shrink with
       the column instead of forcing its content width. */
    min-width: 0;
    max-width: var(--cr-card-cap);
    height: 62px;
    display: flex;
    align-items: stretch;
    overflow: hidden;
    /* Rounded on every corner: overflow:hidden clips the spine to the rounded left edge and the trailing
       chevron to the rounded right edge, so the whole panel reads as one rounded pill. */
    border-radius: 11px;
    background: #fff;
    /* Lift each category group off the band so it reads as a distinct raised card: a deep ambient shadow
       with a tight contact shadow beneath it. */
    box-shadow: 0 6px 16px rgba(15, 42, 54, 0.18), 0 2px 4px rgba(15, 42, 54, 0.1);
}

/* Vertical category spine — same label treatment as the match blocks (TournamentLiveTimeLine .tl-spine).
   The text wraps into extra vertical columns (widening the spine) so a long category name shows in full
   instead of truncating. */
.cr-spine[b-llfrc2tlrm] {
    /* Fixed width (border-box, so the 1px right border is included) — the card's content-derived min/max width
       calc adds exactly this, so it must not vary with the label. Long names clip rather than widen the spine. */
    flex: 0 0 var(--cr-spine-w);
    width: var(--cr-spine-w);
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2px 2px;
    background: #eef3f4;
    border-right: 1px solid rgba(15, 42, 54, 0.08);
}

.cr-spine-txt[b-llfrc2tlrm] {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    max-height: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    text-align: center;
    font-size: 0.5em;
    font-weight: 800;
    text-transform: uppercase;
    line-height: 1.3;
    color: #0f2a36;
    opacity: 0.72;
}

/* Chevron flow runs edge-to-edge: no padding, so the chevrons fill the full cell height. It simply takes the
   card's width minus the fixed spine; the chevrons inside then split that width equally. The card's own
   min/max width (driven by --n) is what bounds the chevrons between their floor and cap. */
.cr-flow[b-llfrc2tlrm] {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-wrap: nowrap;
    align-items: stretch;
}

/* Each round is a real action button shaped as a forward-pointing chevron. Width is bounded (it neither
   stretches on a wide screen nor grows unbounded) and can shrink on a phone. The edge is a crisp 1px
   border made the only way a clip-path silhouette can carry one: the button is filled with --edge and an
   inner ::before (the --face) is clipped to the SAME chevron eroded 1px perpendicular to every edge, so a
   uniform band of --edge shows through — including along the diagonal point and notch — with no mitre fuzz.
   The erosion offsets (1.445 corner / 12.695 shoulder / 1.07 tip / 13.07 notch) are the per-edge bisector
   distances for a 1px border on this 12px-tip chevron; --edge / --face recolour it per state. */
.cr-chv[b-llfrc2tlrm] {
    position: relative;
    /* Chevrons split their flow's width equally (flex-grow from a 0 basis), so they're all the same width
       within a card and shrink in lock-step as the flow shrinks — from the cap (when the flow is at its full
       width) down to the floor (when the flow hits its min-width). border-box keeps the cap the whole chevron
       incl. padding. */
    box-sizing: border-box;
    flex: 1 1 0;
    min-width: 0;
    max-width: var(--cr-chv-cap);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    appearance: none;
    border: 0;
    border-radius: 9px;
    cursor: pointer;
    padding: 0 10px;
    color: #7c8b92;
    /* The 12px tip slots into the next 12px notch; backing off by 3px (the --cr-chv-overlap shared with the
       flow's width formula) leaves a 3px gap between consecutive chevrons. */
    margin-left: calc(-1 * var(--cr-chv-overlap));
    --edge: #cbd3d6;
    --face: #eef1f2;
    background: var(--edge);
    transition: filter 0.12s ease;
    filter: drop-shadow(0 1px 2px rgba(15, 42, 54, 0.18));
    clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%, 12px 50%);
}

/* Inner face — the 1px-eroded chevron; the --edge fill behind shows as a uniform border. */
.cr-chv[b-llfrc2tlrm]::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    background: var(--face);
    clip-path: polygon(1.445px 1px, calc(100% - 12.695px) 1px, calc(100% - 1.07px) 50%, calc(100% - 12.695px) calc(100% - 1px), 1.445px calc(100% - 1px), 13.07px 50%);
}

/* Keep the label, count, glyph and progress strip above the inner face. */
.cr-chv > *[b-llfrc2tlrm] {
    position: relative;
    z-index: 1;
}

.cr-chv:first-child[b-llfrc2tlrm] {
    margin-left: 0;
    padding-left: 6px;
    /* Zero the base 9px radius: with a clip-path present the browser clips to the polygon ∩ the
       rounded border-box, so the corner-to-corner left edge would otherwise render rounded. */
    border-radius: 0;
    clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%);
}

/* First cell's left edge is the rounded pill end (clipped to the cell's 11px radius). The face must round
   to match — a 10px-radius rect inset 1px — otherwise its square corner pokes past the rounded outline and
   the 1px border thins to nothing at the rounded corners. The 1px top/left/bottom inset moves to the box
   (so border-radius can round the corners); the clip-path then only carves the right-pointing tip, riding
   the box edges (0 / 100%) on the other three sides. */
.cr-chv:first-child[b-llfrc2tlrm]::before {
    inset: 1px 0 1px 1px;
    border-radius: 0;
    clip-path: polygon(0 0, calc(100% - 12.695px) 0, calc(100% - 1.07px) 50%, calc(100% - 12.695px) 100%, 0 100%);
}

.cr-chv:last-child[b-llfrc2tlrm] {
    padding-right: 10px;
    /* Zero the base 9px radius (same reason as the first cell): with a clip-path present the browser clips to
       the polygon ∩ the rounded border-box, so the notch's convex corners would render rounded while the face
       stays sharp — and the 1px border vanishes there. The right pill end stays rounded via the cell's
       overflow clip, not this radius. */
    border-radius: 0;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 12px 50%);
}

/* Last cell's right edge is the rounded pill end (clipped to the cell's 11px radius) — mirror of the first
   cell: the face rounds to match (10px radius inset 1px) so the 1px border stays uniform around the rounded
   corners instead of vanishing where a square face corner met the rounded outline. The 1px top/right/bottom
   inset moves to the box; the clip-path only carves the left notch, riding the box edges on the other sides. */
.cr-chv:last-child[b-llfrc2tlrm]::before {
    inset: 1px 1px 1px 0;
    border-radius: 0 10px 10px 0;
    clip-path: polygon(1.445px 0, 100% 0, 100% 100%, 1.445px 100%, 13.07px 50%);
}

/* Sole round is a plain rectangle: square left, rounded right — both the --edge fill and the inner face
   round their right corners (no clip-path here, so border-radius works) for a clean 1px rounded border. */
.cr-chv:first-child:last-child[b-llfrc2tlrm] {
    clip-path: none;
    border-radius: 0 11px 11px 0;
}

.cr-chv:first-child:last-child[b-llfrc2tlrm]::before {
    clip-path: none;
    inset: 1px;
    border-radius: 0 10px 10px 0;
}

/* Button affordance: darken the background on hover, deeper on click — no vertical movement. */
.cr-chv:hover[b-llfrc2tlrm] {
    filter: brightness(0.95) drop-shadow(0 1px 2px rgba(15, 42, 54, 0.18));
}

.cr-chv:active[b-llfrc2tlrm] {
    filter: brightness(0.9) drop-shadow(0 1px 1px rgba(15, 42, 54, 0.2));
}

.cr-chv:focus-visible[b-llfrc2tlrm] {
    outline: 2px solid var(--brand-primary, #0ea5b7);
    outline-offset: -2px;
}

.cr-rn[b-llfrc2tlrm] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    max-width: 100%;
    min-width: 0;
}

/* Live beacon: a small coral dot in front of the round name, vertically centred with it. */
.cr-dot[b-llfrc2tlrm] {
    display: none;
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--brand-accent, #ff5e7e);
    box-shadow: 0 0 5px rgba(255, 94, 126, 0.7);
}

.cr-chv.live .cr-dot[b-llfrc2tlrm] {
    display: inline-block;
    animation: cr-pulse-b-llfrc2tlrm 1.4s infinite;
}

@keyframes cr-pulse-b-llfrc2tlrm {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

.cr-rn-t[b-llfrc2tlrm] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 9px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    line-height: 1;
}

.cr-ct[b-llfrc2tlrm] {
    font-size: 14px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.cr-ct small[b-llfrc2tlrm] {
    font-size: 9px;
    opacity: 0.62;
}

.cr-gl[b-llfrc2tlrm] {
    font-size: 19.5px;
    line-height: 1;
}

/* Progress strip along the chevron base — only on started/finished rounds. */
.cr-pf[b-llfrc2tlrm] {
    position: absolute;
    left: 14px;
    right: 18px;
    bottom: 12px;
    height: 5px;
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.08);
    overflow: hidden;
    z-index: 1;
}

.cr-pf i[b-llfrc2tlrm] {
    display: block;
    height: 100%;
    width: var(--p, 0%);
    border-radius: 3px;
}

/* ── states ─────────────────────────────────────────────────────────── */
/* Live: green border (same as completed) around a white face — greyscale label,
   green count + green bar, plus the coral live dot. */
.cr-chv.live[b-llfrc2tlrm] {
    --edge: #74c993;
    color: #33444c;
}

.cr-chv.live[b-llfrc2tlrm]::before {
    background: #fff;
}

.cr-chv.live .cr-rn-t[b-llfrc2tlrm] {
    color: #5b7280;
}

.cr-chv.live .cr-ct[b-llfrc2tlrm] {
    color: #15803d;
}

.cr-chv.live .cr-pf i[b-llfrc2tlrm] {
    background: #16a34a;
}

/* Ready to start: solid coral gradient + white text — matches the selected category tab on the overview.
   No inner face: the gradient fills the whole chevron, so suppress the ::before. A ready round is the one
   action a viewer is waiting on, so the whole chevron pulses (its coral glow swells and fades) to draw the
   organiser to the play button. */
.cr-chv.ready[b-llfrc2tlrm] {
    background: linear-gradient(135deg, var(--brand-accent-warm, #ff7e5f), var(--brand-accent, #ff5e7e));
    color: #fff;
    /* The glow swells and fades so the whole chevron breathes. Scaling the chevron itself would clip on the
       card's overflow:hidden, so the strongest visual cue is the play glyph pulsing (see .cr-gl below). */
    animation: cr-ready-glow-b-llfrc2tlrm 1.4s ease-in-out infinite;
}

@keyframes cr-ready-glow-b-llfrc2tlrm {
    0%, 100% { filter: drop-shadow(0 3px 7px rgba(255, 94, 126, 0.3)); }
    50% { filter: drop-shadow(0 6px 16px rgba(255, 94, 126, 0.85)); }
}

/* The play glyph is the actual affordance, so pulse it prominently — a clear scale/opacity throb that reads
   as "press me" and, sitting inside the chevron, never clips against the card edge. */
.cr-chv.ready .cr-gl[b-llfrc2tlrm] {
    animation: cr-ready-play-b-llfrc2tlrm 1.4s ease-in-out infinite;
    transform-origin: center;
}

@keyframes cr-ready-play-b-llfrc2tlrm {
    0%, 100% { transform: scale(1); opacity: 0.8; }
    50% { transform: scale(1.28); opacity: 1; }
}

/* Respect reduced-motion: hold the ready state and the live dot steady, no throb. */
@media (prefers-reduced-motion: reduce) {
    .cr-chv.ready[b-llfrc2tlrm],
    .cr-chv.ready .cr-gl[b-llfrc2tlrm],
    .cr-chv.live .cr-dot[b-llfrc2tlrm] {
        animation: none;
    }
}

.cr-chv.ready[b-llfrc2tlrm]::before {
    display: none;
}

.cr-chv.ready:hover[b-llfrc2tlrm] {
    filter: brightness(0.95) drop-shadow(0 4px 9px rgba(255, 94, 126, 0.34));
}

.cr-chv.ready .cr-rn-t[b-llfrc2tlrm],
.cr-chv.ready .cr-gl[b-llfrc2tlrm] {
    color: #fff;
}

/* Completed: stays green — green face with a green border. */
.cr-chv.completed[b-llfrc2tlrm] {
    --edge: #74c993;
    --face: #dcf3e4;
    color: #15803d;
}

.cr-chv.completed .cr-pf i[b-llfrc2tlrm] {
    background: #16a34a;
}

/* Not started / locked: greyscale, lock glyph, recedes (border only, no elevation). */
.cr-chv.locked[b-llfrc2tlrm] {
    --edge: #cfd6d9;
    --face: #eef1f2;
    color: #9aa6ac;
    filter: none;
}

.cr-chv.locked:hover[b-llfrc2tlrm] {
    filter: none;
}
/* /Components/TournamentLiveTimeLine.razor.rz.scp.css */
/* ── Gantt timeline — full bleed: no border, no radius, spans the content ─── */
/* The scroll container: fills the page's scroll-region height and owns both
   axes (sticky header, horizontal court overflow). Scrolling lives here, NOT on
   .tl-gantt, so the gantt can size to its full content width and the NOW marker
   (absolutely positioned against the gantt) shares the same coordinate space as
   the match blocks instead of being measured against the narrower viewport. */
.tl-scroll[b-vkunih1gm4] {
    flex: 1;
    overflow: auto;
    position: relative;
}

.tl-gantt[b-vkunih1gm4] {
    background: #fff;
    position: relative;
    display: flex;
    flex-direction: column;
    /* Grow to the full content width when the courts overflow, but never shrink
       below the visible viewport so the layout stays flush when it all fits. */
    width: max-content;
    min-width: 100%;
    min-height: 100%;
}

/* Per-hour column width (--tl-colw) and the per-block minimum width (--tl-minblock) are set inline
   from the component's ColumnWidthPx / MinBlockWidthPx constants, so the CSS track and the C# lane-
   packing maths share one source of truth. The compact (score-less staging) preview passes a narrower
   column. */
.tl-gantt[b-vkunih1gm4] {
    /* Sticky court-label column width; pages with richer court headers (e.g. the
       schedule staging preview's group chips) override it via ::deep. */
    --tl-courtw: 150px;
}

/* The narrow score-less preview is all about the names, so keep them visible (wrapping to a second
   line if needed) instead of collapsing to avatars in narrow boxes — overriding the container query
   below. Teams of 3+ with no team name still force avatars (.is-forced); their names can't fit. */
.tl-compact .tl-block .tl-names[b-vkunih1gm4] {
    display: flex;
}

.tl-compact .tl-block .tl-avs:not(.is-forced)[b-vkunih1gm4] {
    display: none;
}

.tl-ghead[b-vkunih1gm4] {
    display: grid;
    grid-template-columns: var(--tl-courtw, 150px) repeat(var(--tl-cols, 8), minmax(var(--tl-colw), 1fr));
    border-bottom: 1px solid #e7ebee;
    position: sticky;
    top: 0;
    background: #eef3f4;
    z-index: 3;
    /* Fixed header — only the rows below scroll. */
    flex: 0 0 auto;
}

.tl-ghead .tl-cell[b-vkunih1gm4] {
    padding: 5px 10px;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.06em;
    color: #5b7280;
    text-transform: uppercase;
    text-align: center;
    border-left: 1px solid #e7ebee;
}

.tl-ghead .tl-cell:first-child[b-vkunih1gm4] {
    border-left: 0;
    text-align: left;
    /* Keep the Court header pinned while the track scrolls horizontally. */
    position: sticky;
    left: 0;
    background: #eef3f4;
    z-index: 4;
}

/* Court header cell hosting optional injected content (the live board's reorganise toggle): the control
   leads on the left edge with the label right after it, and the trimmed vertical padding keeps the header
   row at its usual height even with a compact icon button inside. */
.tl-cell-court[b-vkunih1gm4] {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    padding-top: 3px;
    padding-bottom: 3px;
}

/* Positioned-tick header: the track is one cell holding absolutely-placed hour ticks, so labels can sit
   on full hours regardless of where the window opens. */
.tl-ghead.tl-headpos[b-vkunih1gm4] {
    grid-template-columns: var(--tl-courtw, 150px) 1fr;
}

.tl-headtrack[b-vkunih1gm4] {
    position: relative;
}

.tl-tick[b-vkunih1gm4] {
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    padding-left: 6px;
    border-left: 1px solid #e7ebee;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.06em;
    color: #5b7280;
    text-transform: uppercase;
    white-space: nowrap;
}

.tl-row[b-vkunih1gm4] {
    /* Lane geometry — a stacked lane is 104px tall with a 6px gap between lanes and a 7px band of
       padding top/bottom (so a single lane is the same 118px band as before). */
    --tl-lane-h: 104px;
    --tl-lane-gap: 6px;
    --tl-pad: 7px;
    --tl-lanes: 1;
    display: grid;
    grid-template-columns: var(--tl-courtw, 150px) repeat(var(--tl-cols, 8), minmax(var(--tl-colw), 1fr));
    border-bottom: 1px solid #f1f5f6;
    position: relative;
    /* Court rows hold a fixed-band height: the match box is at least 100px, plus
       the 7px top/bottom gap around it (≈114px lane), and may grow a little more. */
    flex: 0 0 auto;
    min-height: 118px;
    max-height: 150px;
}

/* A court whose short matches overlap once clamped to the minimum width: the row grows to stack them
   into N fixed-height lanes (no upper cap — it grows as tall as the busiest moment needs). */
.tl-row.tl-laned[b-vkunih1gm4] {
    max-height: none;
    min-height: calc(var(--tl-pad) * 2 + var(--tl-lanes) * var(--tl-lane-h) + (var(--tl-lanes) - 1) * var(--tl-lane-gap));
}

.tl-row:last-child[b-vkunih1gm4] {
    border-bottom: 0;
}

.tl-court-lbl[b-vkunih1gm4] {
    display: flex;
    flex-direction: column;
    justify-content: center;
    justify-items: center;
    align-items: center;
    padding: 8px;
    font-weight: 800;
    font-size: 13px;
    color: #0f2a36;
    background: #fafdfe;
    border-right: 1px solid #e7ebee;
    position: sticky;
    left: 0;
    z-index: 2;
}

.tl-court-name[b-vkunih1gm4] {
    display: flex;
    align-items: center;
    gap: 6px;
}

.tl-court-icon[b-vkunih1gm4] {
    font-size: 11px;
    color: #94a3b8;
}

.tl-court-sub[b-vkunih1gm4] {
    font-size: 10px;
    color: #5b7280;
    font-weight: 700;
    margin-top: 2px;
}

/* ── Reorganise-mode court header ────────────────────────────────────────────
   When the host supplies CourtHeaderExtra (the schedule staging page and the live board's reorganise
   mode), the court column hosts a rotated court-name spine beside the group strips. The width is driven
   by --ts-courtw, set inline on the host's scroll element and inherited down to the gantt. Owning these
   rules here (rather than duplicating ::deep overrides in each host page) keeps both hosts in sync. The
   .tl-gantt.tl-grouped-header compound (3 classes after scoping) outranks the base single-class rules. */
.tl-gantt.tl-grouped-header[b-vkunih1gm4] {
    --tl-courtw: var(--ts-courtw, 170px);
}

/* Lay the rotated court-name spine (left) and the group strips (right) on ONE row. */
.tl-gantt.tl-grouped-header .tl-court-lbl[b-vkunih1gm4] {
    flex-direction: row;
    align-items: stretch;
    justify-content: flex-start;
    gap: 8px;
    padding: 6px 8px;
}

/* Court name as a slim vertical spine reading top → bottom. */
.tl-gantt.tl-grouped-header .tl-court-name[b-vkunih1gm4] {
    flex: none;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    text-orientation: mixed;
    align-items: center;
    justify-content: center;
    gap: 0;
    font-weight: 800;
    font-size: 13px;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* Each court label is a sticky stacking context (z-index 2), so an open add-group menu would paint under
   the following rows. Lift the label above its siblings while its menu is open. .ts-group-add-menu lives
   in ScheduleReorganizer's scope, so ::deep drops scoping past the gantt to match it. */
.tl-gantt.tl-grouped-header[b-vkunih1gm4]  .tl-court-lbl:has(.ts-group-add-menu) {
    z-index: 20;
}

/* Trailing spacer: takes up any height left below the last court row so the sticky
   court-label column's grey background extends to the bottom of the viewport. */
.tl-filler[b-vkunih1gm4] {
    display: grid;
    grid-template-columns: var(--tl-courtw, 150px) repeat(var(--tl-cols, 8), minmax(var(--tl-colw), 1fr));
    flex: 1 0 auto;
    min-height: 0;
}

.tl-track[b-vkunih1gm4] {
    position: relative;
    grid-column: 2 / -1;
}

.tl-track[b-vkunih1gm4]::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: repeating-linear-gradient(to right, transparent, transparent calc(12.5% - 1px), #f1f5f6 calc(12.5% - 1px), #f1f5f6 12.5%);
    pointer-events: none;
}

/* ── Match block — Scoreboard ──────────────────────────────────────────────── */
.tl-block[b-vkunih1gm4] {
    position: absolute;
    top: 7px;
    bottom: 7px;
    /* Never narrower than the minimum (set inline from MinBlockWidthPx) so an instant score or a
       walkover still shows its full scoreboard; overlaps this causes are resolved into lanes. */
    min-width: var(--tl-minblock, 180px);
    border-radius: 10px;
    overflow: hidden;
    /* White inside for every state — the state reads from the border + glow, not a fill. */
    background: #fff;
    border: 1px solid #e7ebee;
    display: flex;
    flex-direction: column;
    /* Width of the leading-edge category spine that the board reserves room for. */
    --tl-spine-w: 16px;
    /* Lets the scoreboard query the block's own width so narrow boxes can swap player
       names for compact initial-avatars (see the @container rule below). */
    container-type: inline-size;
    transition: opacity 0.15s ease, box-shadow 0.12s ease;
}

/* In a multi-lane row each block is a fixed-height card pinned to its lane (top derives from the
   0-based --tl-lane) rather than filling the band top-to-bottom. Single-lane rows keep the original
   top/bottom fill, so the untouched common case (and the staging preview) looks exactly as before. */
.tl-row.tl-laned .tl-block[b-vkunih1gm4] {
    bottom: auto;
    height: var(--tl-lane-h);
    top: calc(var(--tl-pad) + var(--tl-lane, 0) * (var(--tl-lane-h) + var(--tl-lane-gap)));
}

/* Organiser live board: the whole block is a button into the result editor. */
.tl-block.tl-clickable[b-vkunih1gm4] {
    cursor: pointer;
}

.tl-block.tl-clickable:hover[b-vkunih1gm4] {
    /* The primary hover ring must take precedence over every state's pulsing box-shadow animation
       (live / overdue / delayed / highlight) — a running animation otherwise wins the cascade over a
       plain :hover box-shadow. Pause the animation and pin the primary border so hover always wins. */
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 2px var(--brand-primary), 0 6px 16px rgba(14, 165, 183, 0.22);
    animation: none;
}

/* ── Category spine — vertical band on the board's leading edge ───────────────
   Lives inside the board so it starts below the caption header (leaving the top-left
   corner free for the time). Same grey band + hairline divider as the caption, so it
   frames the box rather than colour-coding it. */
.tl-spine[b-vkunih1gm4] {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: var(--tl-spine-w, 16px);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: #eef3f4;
    /* Hairline separating the spine from the white score area. */
    border-right: 1px solid rgba(15, 42, 54, 0.08);
    /* Stays below the sticky court-label column (z-index 2) so it slides behind it
       on horizontal scroll. */
    z-index: 1;
}

.tl-spine-txt[b-vkunih1gm4] {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    max-height: 100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 8.5px;
    font-weight: 800;
    text-transform: uppercase;
    line-height: 1;
    /* Mirrors the caption's .tl-pool muting (inherited ink at 0.7). */
    opacity: 0.7;
}

/* caption: time (left) · LIVE / walkover (centre) · group name (right) */
.tl-cap[b-vkunih1gm4] {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0;
    padding: 1px 8px;
    /* Fixed grey header band (same on every state, matching the timeline hour-header), divided
       from the board by a hairline. */
    background: #eef3f4;
    border-bottom: 1px solid rgba(15, 42, 54, 0.08);
    /* Match the block's rounded top so the band keeps its corners in its own right, rather than relying
       on the block's overflow:hidden to trim them. */
    border-top-left-radius: 9px;
    border-top-right-radius: 9px;
}

/* Pin every cell to the single header row. The cells declare explicit columns (time→1,
   live/grip→2, group→3) that no longer ascend in DOM order, so without this the default
   sparse auto-flow would push the later-DOM/earlier-column cells onto new rows. */
.tl-cap > *[b-vkunih1gm4] {
    grid-row: 1;
}

/* Right caption cell: the plain-text bracket-round / group label, occupying column 3. */
.tl-poolwrap[b-vkunih1gm4] {
    grid-column: 3;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    min-width: 0;
}

.tl-pool[b-vkunih1gm4] {
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.05em;
    opacity: 0.7;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Later-round match whose participants aren't decided yet (a placeholder slot). Reads as a reserved,
   still-forming bracket slot: a dashed white card whose participant labels ride inside a softly
   sweeping grey pill, so an undecided slot reads as "waiting to be filled" rather than an empty 0–0
   board. These blocks never carry a score or a live/overdue pulse — the host pins them to the
   Scheduled state regardless of clock time. */
.tl-block.tl-future[b-vkunih1gm4] {
    border-style: dashed;
    border-color: #bcd3d8;
    background: #fff;
}

/* Skip seed-filled sides (the staging preview fills these same cells with a seed colour during
   assignment) — a pill there would paint over the seed fill. Every other placeholder side, on both
   the live board and the staging preview, gets the pill. */
    .tl-block.tl-future .tl-id:not(.tl-seedfill) .tl-names[b-vkunih1gm4] {
        background: linear-gradient(90deg, #f2f6f7 25%, #ebecec 37%, #f2f6f7 63%);
        background-size: 400% 100%;
        border-radius: 4px;
        padding: 4px 11px;
        animation: tl-future-sweep-b-vkunih1gm4 1.6s ease-in-out infinite;
    }

/* Provisional names read a touch lighter than a decided box's ink. */
    .tl-block.tl-future .tl-pl[b-vkunih1gm4] {
        color: #80969f;
    }

@keyframes tl-future-sweep-b-vkunih1gm4 {
    0% {
        background-position: 100% 0;
    }
    100% {
        background-position: 0 0;
    }
}

.tl-when[b-vkunih1gm4] {
    grid-column: 1;
    font-size: 9px;
    font-weight: 800;
    color: #5b7280;
    text-align: left;
    white-space: nowrap;
}

.tl-live[b-vkunih1gm4] {
    grid-column: 2;
    justify-self: center;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--brand-primary-deep, #0a6f7d);
    white-space: nowrap;
}

.tl-live[b-vkunih1gm4]::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--brand-accent, #ff5e7e);
    box-shadow: 0 0 7px rgba(255, 94, 126, 0.75);
    animation: tl-now-pulse-b-vkunih1gm4 1.4s infinite;
}

.tl-live.tl-wo[b-vkunih1gm4]::before {
    display: none;
}

/* Orange variant of the caption pulse — overdue/delayed reuse the dot in amber instead of coral.
   The label (DELAYED, delayed-only) takes the same amber ink. */
.tl-live.tl-amber[b-vkunih1gm4] {
    color: var(--amber-deep, #b45309);
}

.tl-live.tl-amber[b-vkunih1gm4]::before {
    background: #d97706;
    box-shadow: 0 0 7px rgba(217, 119, 6, 0.7);
}

/* ── Unsettled result — caption pill hung from the block's top edge ───────────
   A played match whose score isn't agreed yet. Deliberately an OVERLAY rather than a
   state: the completed block keeps its exact settled-grey fill, border and size, and this
   pill is simply laid on top, so a result going from unconfirmed to confirmed only removes
   the pill instead of re-styling the card. It is centred on the caption band's middle slot —
   the one cell a completed match leaves empty (that cell only ever carries LIVE / W-O /
   DELAYED) — so the time on the left and the group label on the right stay readable. The
   type is kept tight for the same reason: every px of pill width is a px of the group label
   it could reach on a block whose category string is long. */
.tl-review[b-vkunih1gm4] {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    /* Above the caption (which the delayed state lifts to z-index 1) and the podium medal
       column (z-index 2), so the pill is never painted over. */
    z-index: 4;
    padding: 2px 8px 3px;
    /* Square on top, rounded below — reads as hung from the card's top edge. */
    border-radius: 0 0 8px 8px;
    font-size: 8.5px;
    font-weight: 900;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #fff;
    white-space: nowrap;
    /* Purely informational: clicks fall through to the block, which opens the result editor. */
    pointer-events: none;
}

/* Amber — entered but still waiting on a team's answer (mirrors the overdue/delayed key). */
.tl-review-pending[b-vkunih1gm4] {
    background: linear-gradient(180deg, #d97706, #b45309);
    box-shadow: 0 3px 9px rgba(180, 83, 9, 0.42);
}

/* Rose — a team contested the score, so the organiser has to look at it. A hue used nowhere
   else on the board, so it can't be mistaken for the coral live state. */
.tl-review-disputed[b-vkunih1gm4] {
    background: linear-gradient(180deg, #e11d48, #9f1239);
    box-shadow: 0 3px 9px rgba(159, 18, 57, 0.42);
}

/* scoreboard grid — column template is set inline per block (names | set cells | gap | count) so
   leftover width flows to the names. */
.tl-board[b-vkunih1gm4] {
    flex: 1;
    display: grid;
    grid-template-columns: 1fr;
    grid-auto-rows: 1fr;
    align-items: stretch;
    min-height: 0;
    /* Anchors the absolutely-positioned category spine and reserves its strip on the
       leading edge, so the spine starts below the caption rather than spanning it. */
    position: relative;
    padding-left: var(--tl-spine-w);
}

.tl-trow[b-vkunih1gm4] {
    display: contents;
}

.tl-id[b-vkunih1gm4] {
    display: flex;
    align-items: center;
    padding: 0 6px;
    min-width: 0;
    overflow: hidden;
}

/* The default content of a name cell: player labels that wrap to a second line when the pair
   doesn't fit. Swapped out for .tl-avs on narrow blocks via the container query below. */
.tl-names[b-vkunih1gm4] {
    display: flex;
    flex-wrap: wrap;
    align-content: center;
    align-items: center;
    gap: 0 8px;
    min-width: 0;
    overflow: hidden;
}

/* Compact initial-avatars shown only when the block is too narrow for full names. */
.tl-avs[b-vkunih1gm4] {
    display: none;
    align-items: center;
    gap: 4px;
    --avatar-size: 22px;
}

/* Teams of 3+ with no team name render as avatars at every width (names would overflow the box). */
.tl-avs.is-forced[b-vkunih1gm4] {
    display: inline-flex;
    flex-wrap: wrap;
}

/* When the match block is narrower than its labels can handle, drop the text names and show the
   players as small initial-avatars instead — the box stays legible instead of clipping to stubs. */
@container (max-width: 170px) {
    .tl-names[b-vkunih1gm4] {
        display: none;
    }

    .tl-avs[b-vkunih1gm4] {
        display: inline-flex;
    }
}

.tl-trow + .tl-trow .tl-id[b-vkunih1gm4],
.tl-trow + .tl-trow .tl-set[b-vkunih1gm4],
.tl-trow + .tl-trow .tl-gap[b-vkunih1gm4],
.tl-trow + .tl-trow .tl-cnt[b-vkunih1gm4] {
    border-top: 1px dashed rgba(15, 42, 54, 0.10);
}

/* players wrap to a second line when the pair doesn't fit; a single long name truncates */
.tl-pl[b-vkunih1gm4] {
    font-size: 11px;
    font-weight: 700;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    max-width: 100%;
}

.tl-set[b-vkunih1gm4] {
    display: grid;
    place-items: center;
    font-size: 10px;
    font-weight: 700;
    color: #5b7280;
    font-variant-numeric: tabular-nums;
}

.tl-set.tl-set-won[b-vkunih1gm4] {
    color: #0f2a36;
    font-weight: 800;
}

.tl-cnt[b-vkunih1gm4] {
    display: grid;
    place-items: center;
    font-size: 16px;
    font-weight: 900;
    color: #5b7280;
    font-variant-numeric: tabular-nums;
    background: #eef1f3;
}

/* ── Outcome (completed matches only) — bolder ink cue ───────────────────────
   Greyscale, colour-only winner cue: the winning row gets bolder ink; the loser
   fades back. Driven entirely by the recorded WinnerTeamId flag (mapped to
   .tl-win/.tl-lose/.tl-draw on the host page) — never recomputed from the score
   here. */
.tl-trow.tl-win .tl-pl[b-vkunih1gm4] {
    color: #0f2a36;
    font-weight: 800;
}

/* The winning side's set count matches its bolded set-point cells (.tl-set-won) rather than reading green. */
.tl-trow.tl-win .tl-cnt[b-vkunih1gm4] {
    color: #0f2a36;
}

.tl-trow.tl-lose .tl-pl[b-vkunih1gm4],
.tl-trow.tl-lose .tl-cnt[b-vkunih1gm4] {
    color: #9aa0a4;
}

.tl-trow.tl-draw .tl-pl[b-vkunih1gm4],
.tl-trow.tl-draw .tl-cnt[b-vkunih1gm4] {
    color: #0f2a36;
}

/* walkover: the players didn't play it out */
.tl-block.cancelled .tl-pl[b-vkunih1gm4] {
    color: #9aa0a4;
    text-decoration: line-through;
}

/* ── Rating-bar labels (actual players) ───────────────────────────────────────
   An actual player renders as a PlayerLabel (name over a thin rating bar) carrying
   the .tl-pl class, so it sits as one flex item in .tl-names alongside any team-name
   fallback span. Its name drops its own colour/weight to inherit, so the outcome and
   state ink cues below (win/lose/draw/walkover/future/seedfill) keep driving it —
   ::deep reaches across into the child component's markup. */
.tl-names[b-vkunih1gm4]  .player-label.tl-pl {
    flex: 0 1 auto;
    min-width: 0;
    font-weight: 700;
}

.tl-names[b-vkunih1gm4]  .player-label.tl-pl .player-label-name {
    font-size: 11px;
    line-height: 1.25;
    font-weight: inherit;
    color: inherit;
}

/* Nothing here un-clips .tl-block / .tl-id / .tl-names for PlayerLabel's rating card, and nothing should.
   The card is a popover painted in the top layer (see .player-label-tip in app.css), so it already clears
   every overflow and z-index between it and the viewport. Un-clipping these three used to be how the card
   escaped, and it could never be made to work: .tl-scroll owns both scroll axes and must keep clipping, so
   a card on a row near the top was still cut off by it and buried under the sticky header. */

.tl-trow.tl-win[b-vkunih1gm4]  .player-label.tl-pl {
    color: #0f2a36;
    font-weight: 800;
}

.tl-trow.tl-lose[b-vkunih1gm4]  .player-label.tl-pl {
    color: #9aa0a4;
}

.tl-trow.tl-draw[b-vkunih1gm4]  .player-label.tl-pl {
    color: #0f2a36;
}

.tl-block.cancelled[b-vkunih1gm4]  .player-label.tl-pl {
    color: #9aa0a4;
    text-decoration: line-through;
}

.tl-block.tl-future[b-vkunih1gm4]  .player-label.tl-pl {
    color: #80969f;
}

.tl-id.tl-seedfill[b-vkunih1gm4]  .player-label.tl-pl {
    color: #fff;
}

/* ── States: completed reads grey (played, settled), scheduled white (upcoming), live keeps its
   coral glow, overdue/delayed carry an orange attention tint ─────────────────── */
.tl-block.completed[b-vkunih1gm4] {
    background: #eaeff1;
    border-color: #d7dee1;
}

/* Upcoming match — clean white card. */
.tl-block.scheduled[b-vkunih1gm4] {
    background: #fff;
    border-color: #d7dee1;
}

.tl-block.cancelled[b-vkunih1gm4] {
    border-color: #e2d6d6;
}

/* Ongoing match within its estimated duration — reads as currently in play. */
.tl-block.live[b-vkunih1gm4] {
    border-color: var(--brand-accent, #ff5e7e);
    animation: tl-live-pulse-b-vkunih1gm4 1.6s ease-in-out infinite;
}

/* Ongoing match that has run past its estimated max duration (overdue) or past twice its estimate
   (delayed — its real status can no longer be inferred): both keep a WHITE scoreboard body (still in
   play / incomplete), framed by amber header strips, with an amber border + attention pulse. Delayed
   adds the DELAYED label (in markup) and the hollow "?" watermark below. */
.tl-block.overdue[b-vkunih1gm4],
.tl-block.delayed[b-vkunih1gm4] {
    background: #fff;
    border-color: #d97706;
    animation: tl-overdue-pulse-b-vkunih1gm4 1.4s ease-in-out infinite;
}

/* The framing strips — top caption, left category spine, right won-set gutter — take a light amber
   wash; the scoreboard body (player names + per-set scores) stays white. */
.tl-block.overdue .tl-cap[b-vkunih1gm4],
.tl-block.overdue .tl-spine[b-vkunih1gm4],
.tl-block.overdue .tl-cnt[b-vkunih1gm4],
.tl-block.delayed .tl-cap[b-vkunih1gm4],
.tl-block.delayed .tl-spine[b-vkunih1gm4],
.tl-block.delayed .tl-cnt[b-vkunih1gm4] {
    background: #fdf2e1;
}

.tl-block.overdue .tl-cap[b-vkunih1gm4],
.tl-block.delayed .tl-cap[b-vkunih1gm4] {
    border-bottom-color: rgba(180, 83, 9, 0.16);
}

.tl-block.overdue .tl-spine[b-vkunih1gm4],
.tl-block.delayed .tl-spine[b-vkunih1gm4] {
    border-right-color: rgba(180, 83, 9, 0.16);
}

/* Header text (caption time + group, category spine), the per-set scores and the won-set count all
   take the same amber ink as the DELAYED label, so the whole card reads in one amber key. */
.tl-block.overdue .tl-when[b-vkunih1gm4],
.tl-block.overdue .tl-pool[b-vkunih1gm4],
.tl-block.overdue .tl-spine-txt[b-vkunih1gm4],
.tl-block.overdue .tl-set[b-vkunih1gm4],
.tl-block.overdue .tl-cnt[b-vkunih1gm4],
.tl-block.delayed .tl-when[b-vkunih1gm4],
.tl-block.delayed .tl-pool[b-vkunih1gm4],
.tl-block.delayed .tl-spine-txt[b-vkunih1gm4],
.tl-block.delayed .tl-set[b-vkunih1gm4],
.tl-block.delayed .tl-cnt[b-vkunih1gm4] {
    color: var(--amber-deep, #b45309);
    opacity: 1;
}

/* Keep the caption + board above the watermark so the "?" reads as a backdrop, not over the text. */
.tl-block.delayed .tl-cap[b-vkunih1gm4],
.tl-block.delayed .tl-board[b-vkunih1gm4] {
    position: relative;
    z-index: 1;
}

/* Hollow "?" watermark behind the delayed board — an amber outline (not a solid fill) so the
   scoreboard underneath stays fully readable. */
.tl-unknown[b-vkunih1gm4] {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: grid;
    place-items: center;
    font-size: 72px;
    font-weight: 900;
    line-height: 1;
    color: transparent;
    -webkit-text-stroke: 2px rgba(180, 83, 9, 0.28);
    pointer-events: none;
    user-select: none;
}

/* ── Highlight — like the live state's coral pulse, but radiating the brand primary ──
   The whole game card tints primary and glows so a player-search match or a selected
   category's games read across the board at a glance. */
.tl-block.tl-hit[b-vkunih1gm4] {
    background: rgba(14, 165, 183, 0.14);
    border-color: var(--brand-primary, #0ea5b7);
    animation: tl-hit-pulse-b-vkunih1gm4 1.6s ease-in-out infinite;
    opacity: 1;
}

/* Keep the caption band tinted too, so the hit reads as one solid primary card. */
.tl-block.tl-hit .tl-cap[b-vkunih1gm4] {
    background: rgba(14, 165, 183, 0.16);
}

/* Primary glow, mirroring tl-live-pulse. */
@keyframes tl-hit-pulse-b-vkunih1gm4 {
    0%, 100% {
        box-shadow: 0 0 5px 0 rgba(14, 165, 183, 0.35);
    }
    50% {
        box-shadow: 0 0 12px 3px rgba(14, 165, 183, 0.65);
    }
}

/* Coral glow, echoing the NOW beacon line. */
@keyframes tl-live-pulse-b-vkunih1gm4 {
    0%, 100% {
        box-shadow: 0 0 5px 0 rgba(255, 94, 126, 0.30);
    }
    50% {
        box-shadow: 0 0 12px 2px rgba(255, 94, 126, 0.55);
    }
}

@keyframes tl-overdue-pulse-b-vkunih1gm4 {
    0%, 100% {
        box-shadow: 0 0 0 0 rgba(217, 119, 6, 0.12);
    }
    50% {
        box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.32);
    }
}

/* ── Move affordance (staging preview only) — grip button + popup menu ───────── */
.tl-act[b-vkunih1gm4] {
    grid-column: 2;
    justify-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 6px;
    background: transparent;
    color: #5b7280;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.tl-act:hover[b-vkunih1gm4],
.tl-act[aria-expanded="true"][b-vkunih1gm4] {
    background: #fff;
    color: #0f2a36;
    border-color: #d8e1ea;
}

.tl-act i[b-vkunih1gm4] {
    font-size: 12px;
}

/* The drag handle: a wide grab bar built from eight single-column dot pips set side by side. It is the
   sole move initiator; the cursor signals grab/grabbing. */
.tl-act.tl-grip[b-vkunih1gm4] {
    width: auto;
    min-width: 0;
    gap: 0;
    padding: 0 2px;
    cursor: grab;
}

.tl-act.tl-grip:active[b-vkunih1gm4] {
    cursor: grabbing;
}

/* Each three-dots glyph carries wide built-in side bearing; pull the columns hard together so the eight
   pips sit close as a dense grip (like the original two-column grip), not strung out across the caption. */
.tl-act.tl-grip i[b-vkunih1gm4] {
    margin-inline: -4px;
}

/* Full-screen click-away layer behind an open menu. */
.tl-act-backdrop[b-vkunih1gm4] {
    position: fixed;
    inset: 0;
    z-index: 10;
    border: 0;
    padding: 0;
    background: transparent;
    cursor: default;
}

/* The menu is rendered at the track level (not inside the block) so the block's overflow:hidden
   can't clip it; positioned at the source block's left edge, just below the caption band. */
.tl-act-pop[b-vkunih1gm4] {
    position: absolute;
    top: 34px;
    z-index: 11;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 190px;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(10, 42, 54, 0.18), 0 0 0 1px rgba(10, 42, 54, 0.06);
    padding: 6px;
}

/* ── Seed fill (staging preview only) — while the seed menu is open ───────────
   Each side of the group's matches is filled solid in its seed colour with white names
   (no border, no pip), so the seeding reads at a glance. The category spine stays put on
   the leading edge so the category remains identifiable during the swap. */
.tl-block.tl-seeded[b-vkunih1gm4] {
    border-color: transparent;
    box-shadow: 0 4px 14px rgba(10, 42, 54, 0.16);
}

.tl-id.tl-seedfill .tl-pl[b-vkunih1gm4] {
    color: #fff;
}

/* Texture over the flat seed fill: a repeating 45° micro-stripe sitting on a soft
   diagonal sheen, both low-contrast so the white names stay the hero. Lifts the block
   off the page (a sport-jersey rhythm) without changing the seed colour itself. */
.tl-id.tl-seedfill[b-vkunih1gm4] {
    position: relative;
}

.tl-id.tl-seedfill[b-vkunih1gm4]::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
        repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.06) 0 7px, rgba(0, 0, 0, 0.05) 7px 14px),
        linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.12));
}

/* Keep the names/avatars above the texture overlay. */
.tl-id.tl-seedfill > *[b-vkunih1gm4] {
    position: relative;
    z-index: 1;
}

/* White hairline between the two seed-filled rows instead of the default dashed grey. */
.tl-trow + .tl-trow .tl-id.tl-seedfill[b-vkunih1gm4] {
    border-top: 1px solid rgba(255, 255, 255, 0.5);
}

/* Just-swapped boxes: the seed fill animates back to white (and the names from white to ink) over
   --tl-seedfade-ms (set inline from SeedFadeMs), so the eye can follow what moved, then it settles plain. */
.tl-block.tl-seedfade .tl-id.tl-seedfill[b-vkunih1gm4] {
    animation: tl-seedfade-bg-b-vkunih1gm4 var(--tl-seedfade-ms, 2500ms) ease-out forwards;
}

.tl-block.tl-seedfade .tl-id.tl-seedfill .tl-pl[b-vkunih1gm4] {
    animation: tl-seedfade-ink-b-vkunih1gm4 var(--tl-seedfade-ms, 2500ms) ease-out forwards;
}

/* Fade the texture overlay away on the same clock, so stripes don't linger on the cleared white box. */
.tl-block.tl-seedfade .tl-id.tl-seedfill[b-vkunih1gm4]::after {
    animation: tl-seedfade-tex-b-vkunih1gm4 var(--tl-seedfade-ms, 2500ms) ease-out forwards;
}

@keyframes tl-seedfade-tex-b-vkunih1gm4 {
    to {
        opacity: 0;
    }
}

@keyframes tl-seedfade-bg-b-vkunih1gm4 {
    to {
        background-color: transparent;
    }
}

@keyframes tl-seedfade-ink-b-vkunih1gm4 {
    from {
        color: #fff;
    }
    to {
        color: #0f2a36;
    }
}

/* ── NOW marker · Beacon — wide gradient line + glowing pill with pulsing dot ─ */
.tl-nowline[b-vkunih1gm4] {
    position: absolute;
    top: 0;
    bottom: 0;
    /* Thickness comes from the component's NowLineWidthPx (set inline as --tl-nowline-w), which also
       shortens the marker's travel range so the line never overhangs the track's right edge. */
    width: var(--tl-nowline-w, 4px);
    /* No z-index here on purpose: an absolute box with z-index:auto creates NO stacking context, so the
       line and pill below can be stacked independently around the sticky header (z-index 3) — the line
       behind it, the pill in front. A z-index here would trap both children inside one context and the
       line would always paint over the header. */
}

.tl-nowline[b-vkunih1gm4]::before {
    content: "";
    position: absolute;
    /* Runs the full height (top:0) at a z-index BELOW the sticky header (z-index 3) but ABOVE the gantt's
       opaque white background and the match blocks (z-index auto). .tl-nowline itself keeps z-index:auto
       (no stacking context), so this ::before and the pill below resolve in the same ancestor context as
       the header: the line (2) sits under the header band — which paints over its top edge so it appears to
       start at the header's bottom — while the pill (5) stays on top. A negative z-index here would drop the
       line behind the opaque .tl-gantt background and hide it entirely. */
    top: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    background: linear-gradient(180deg, var(--brand-accent, #ff5e7e), #ff7e5f);
    box-shadow: 0 0 12px rgba(255, 94, 126, 0.55);
    z-index: 2;
}

.tl-nowtag[b-vkunih1gm4] {
    /* Sticky (not absolute) so vertical content scrolling never carries the pill out of the
       header row — it stays pinned at the top of the scroll viewport. Only `top` is set: with no
       `left`/`right` threshold the pill keeps following the line horizontally (scrolls with the
       track). Centred over the 4px line via the transform's +2px instead of `left:50%`, which would
       otherwise act as a horizontal sticky threshold and detach the pill from the line.
       top:0 seats the pill flush with the line's visible top edge (the scroll viewport's top, where
       the line is clipped at every scroll position). This leaves NO gap above the pill for the line
       to poke through, independent of whether the header band paints over the line — so the pill
       itself always caps the line, in any browser/stacking. */
    position: sticky;
    top: 4px;
    transform: translateX(calc(-50% + var(--tl-nowline-w, 4px) / 2));
    /* Above the sticky header (z-index 3) so the pill stays visible on the time row, while the line
       behind it (z-index 2) is clipped by the header — together they keep the line below the pill. */
    z-index: 5;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: linear-gradient(135deg, var(--brand-accent, #ff5e7e), #ff7e5f);
    color: #fff;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    white-space: nowrap;
    padding: 6px 13px;
    border-radius: 999px;
    box-shadow: 0 5px 14px rgba(255, 94, 126, 0.45);
}

.tl-nowtag[b-vkunih1gm4]::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    animation: tl-now-wave-b-vkunih1gm4 1.5s ease-out infinite;
}

.tl-nowtag[b-vkunih1gm4]::after {
    content: "";
    position: absolute;
    bottom: -8px;
    left: 50%;
    transform: translateX(-50%);
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;
    border-top: 8px solid #ff7e5f;
}

@keyframes tl-now-wave-b-vkunih1gm4 {
    0% {
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    }
    70% {
        box-shadow: 0 0 0 8px rgba(255, 255, 255, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
    }
}

/* Scale/opacity throb for the live-match dot on the board (.tl-live::before). */
@keyframes tl-now-pulse-b-vkunih1gm4 {
    0%, 100% {
        opacity: 1;
        transform: scale(1);
    }
    50% {
        opacity: 0.35;
        transform: scale(0.65);
    }
}

/* Respect reduced-motion: hold every looping timeline animation steady. The state each one signals is
   already carried by colour/border/label, so dropping the motion loses no information. */
@media (prefers-reduced-motion: reduce) {
    .tl-nowtag[b-vkunih1gm4]::before,
    .tl-live[b-vkunih1gm4]::before,
    .tl-block.tl-future .tl-id:not(.tl-seedfill) .tl-names[b-vkunih1gm4],
    .tl-block.live[b-vkunih1gm4],
    .tl-block.overdue[b-vkunih1gm4],
    .tl-block.delayed[b-vkunih1gm4],
    .tl-block.tl-hit[b-vkunih1gm4] {
        animation: none;
    }
}

/* ── Podium finals — gold (championship final) / bronze (3rd-place play-off) ───
   A trophy medal column caps the leading edge in the rank's metal, and the three framing strips —
   top caption, left category spine, right won-set gutter — take a light gold/bronze wash with
   deep-metal ink (mirroring the amber overdue treatment, in medal colours). The scoreboard body
   (player names + per-set scores) is deliberately left untouched. */
.tl-block.podium-gold[b-vkunih1gm4],
.tl-block.podium-bronze[b-vkunih1gm4] {
    /* Reserve the leading gutter the absolutely-positioned medal column fills. The wider box is what
       makes a podium match dropped into a busy slot overlap its neighbour and pack onto a second lane. */
    padding-left: 42px;
}

.tl-block.podium-gold[b-vkunih1gm4] {
    border-color: var(--gold, #e3b341);
    box-shadow: inset 0 0 0 1px var(--gold, #e3b341), 0 6px 18px rgba(154, 107, 0, 0.18);
}

.tl-block.podium-bronze[b-vkunih1gm4] {
    border-color: var(--bronze, #c07b3a);
    box-shadow: inset 0 0 0 1px var(--bronze, #c07b3a), 0 6px 18px rgba(124, 74, 30, 0.18);
}

/* The medal column — a full-height metallic strip on the leading edge holding the trophy + place. */
.tl-medal[b-vkunih1gm4] {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 42px;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    /* Hairline divider from the scoreboard + a soft top sheen, so the flat fill reads as polished metal. */
    box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.12), inset 0 1px 1px rgba(255, 255, 255, 0.4);
}

.tl-medal i[b-vkunih1gm4] {
    font-size: 18px;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
}

.tl-block.podium-gold .tl-medal[b-vkunih1gm4] {
    background: linear-gradient(160deg, var(--gold-light, #fde68a), var(--gold, #e3b341) 55%, var(--gold-deep, #9a6b00));
}

.tl-block.podium-bronze .tl-medal[b-vkunih1gm4] {
    background: linear-gradient(160deg, var(--bronze-light, #e6c39a), var(--bronze, #c07b3a) 55%, var(--bronze-deep, #7c4a1e));
}

/* Header strips — caption (top), category spine (left), won-set gutter (right) — gold wash + deep ink. */
.tl-block.podium-gold .tl-spine[b-vkunih1gm4],
.tl-block.podium-gold .tl-cnt[b-vkunih1gm4] {
    background: #f3e3b0;
}

.tl-block.podium-gold .tl-cap[b-vkunih1gm4] {
    background: linear-gradient(90deg, #fbf2d4, #f3e3b0);
    border-bottom-color: rgba(154, 107, 0, 0.22);
}

.tl-block.podium-gold .tl-spine[b-vkunih1gm4] {
    border-right-color: rgba(154, 107, 0, 0.22);
}

.tl-block.podium-gold .tl-when[b-vkunih1gm4],
.tl-block.podium-gold .tl-pool[b-vkunih1gm4],
.tl-block.podium-gold .tl-spine-txt[b-vkunih1gm4],
.tl-block.podium-gold .tl-cnt[b-vkunih1gm4] {
    color: var(--gold-deep, #9a6b00);
    opacity: 1;
}

/* Bronze counterpart of the same three strips. */
.tl-block.podium-bronze .tl-spine[b-vkunih1gm4],
.tl-block.podium-bronze .tl-cnt[b-vkunih1gm4] {
    background: #ecd6c0;
}

.tl-block.podium-bronze .tl-cap[b-vkunih1gm4] {
    background: linear-gradient(90deg, #f4e6d6, #ecd6c0);
    border-bottom-color: rgba(124, 74, 30, 0.22);
}

.tl-block.podium-bronze .tl-spine[b-vkunih1gm4] {
    border-right-color: rgba(124, 74, 30, 0.22);
}

.tl-block.podium-bronze .tl-when[b-vkunih1gm4],
.tl-block.podium-bronze .tl-pool[b-vkunih1gm4],
.tl-block.podium-bronze .tl-spine-txt[b-vkunih1gm4],
.tl-block.podium-bronze .tl-cnt[b-vkunih1gm4] {
    color: var(--bronze-deep, #7c4a1e);
    opacity: 1;
}
/* /Components/TournamentRegisterDialog.razor.rz.scp.css */
.reg-dialog[b-zyg9cvz903] {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

.reg-dialog-loading[b-zyg9cvz903] {
    display: grid;
    place-items: center;
    padding: 24px;
}

.reg-dialog-empty[b-zyg9cvz903] {
    color: #5b7280;
    font-size: 14px;
    margin: 0;
}

.reg-dialog-steps[b-zyg9cvz903] {
    list-style: none;
    margin: 0 0 4px;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #94a3ad;
}

    .reg-dialog-steps li[b-zyg9cvz903] {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        color: #94a3b8;
    }

        .reg-dialog-steps li.active[b-zyg9cvz903] {
            color: #64748b;
        }

        .reg-dialog-steps li.done[b-zyg9cvz903] {
            color: #16a34a;
        }

    .reg-dialog-steps .step-n[b-zyg9cvz903] {
        width: 22px;
        height: 22px;
        border-radius: 50%;
        display: grid;
        place-items: center;
        background: transparent;
        border: 1.5px solid #94a3b8;
        color: #94a3b8;
        font-size: 12px;
        font-weight: 800;
    }

    .reg-dialog-steps li.active .step-n[b-zyg9cvz903] {
        background: #94a3b8;
        border-color: #94a3b8;
        color: #fff;
    }

    .reg-dialog-steps li.done .step-n[b-zyg9cvz903] {
        background: #16a34a;
        border-color: #16a34a;
        color: #fff;
    }

.reg-dialog-hint[b-zyg9cvz903] {
    color: #5b7280;
    font-size: 13px;
    margin: 0;
}

/* Step 1 — category tab grid (reuses .cat-tab inside) */
.reg-tabs[b-zyg9cvz903] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 8px;
}

.reg-tab[b-zyg9cvz903] {
    text-align: left;
    background: #fff;
    border: 1px solid #e7ebee;
    border-radius: 14px;
    padding: 12px 14px;
    cursor: pointer;
    color: #0f2a36;
    position: relative;
    transition: transform .12s, box-shadow .12s, border-color .12s;
    font: inherit;
}

    .reg-tab:not(.is-active):not(:disabled):hover[b-zyg9cvz903] {
        border-color: transparent;
        color: #fff;
        background: linear-gradient(135deg, var(--brand-accent-warm), var(--brand-accent));
        box-shadow: 0 6px 14px rgba(255, 94, 126, 0.25);
    }

    .reg-tab.is-active[b-zyg9cvz903] {
        border-color: transparent;
        color: #fff;
        background: linear-gradient(135deg, var(--brand-accent-warm), var(--brand-accent));
        box-shadow: 0 8px 18px rgba(255, 94, 126, 0.3);
    }

    .reg-tab:not(.is-active):not(:disabled):hover .cat-tab-sub[b-zyg9cvz903],
    .reg-tab.is-active .cat-tab-sub[b-zyg9cvz903] {
        color: rgba(255, 255, 255, 0.82);
    }

    .reg-tab:not(.is-active):not(:disabled):hover .progress-ring[b-zyg9cvz903],
    .reg-tab.is-active .progress-ring[b-zyg9cvz903] {
        background: conic-gradient(var(--progress-col) calc(var(--progress-pct) * 1%), #fff 0);
        box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.55);
    }

    .reg-tab.is-full[b-zyg9cvz903],
    .reg-tab.is-ineligible[b-zyg9cvz903] {
        opacity: 0.55;
        cursor: not-allowed;
    }

.reg-tab-badge[b-zyg9cvz903] {
    position: absolute;
    top: 8px;
    right: 10px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #dc3545;
}

/* Step 2 — picked category strip */
.reg-picked[b-zyg9cvz903] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: #f7fafb;
    border-radius: 12px;
    flex-wrap: wrap;
}

.reg-picked-chip[b-zyg9cvz903] {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(255, 126, 95, 0.14);
    color: #dc3545;
}

.reg-picked-meta[b-zyg9cvz903] {
    font-size: 12px;
    color: #5b7280;
}

.reg-picked-change[b-zyg9cvz903] {
    margin-left: auto;
    background: transparent;
    border: 0;
    color: #0a6f7d;
    font-weight: 700;
    font-size: 13px;
    cursor: pointer;
}

/* Form field */
.reg-field[b-zyg9cvz903] {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

    .reg-field label[b-zyg9cvz903] {
        font-size: 12px;
        font-weight: 700;
        color: #5b7280;
        letter-spacing: 0.04em;
    }

    .reg-field .form-control[b-zyg9cvz903] {
        padding: 11px 14px;
        border-radius: 10px;
        border: 1px solid #d6dce3;
        background: #fbfdfd;
        font: inherit;
        color: #0f2a36;
    }

        .reg-field .form-control:focus[b-zyg9cvz903] {
            outline: 2px solid #0ea5b7;
            background: #fff;
        }

/* Roster */
.reg-roster-h[b-zyg9cvz903] {
    margin: 6px 0 -2px;
}

.reg-mate[b-zyg9cvz903] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 0;
    position: relative;
}

    .reg-mate.reg-mate-captain[b-zyg9cvz903],
    .reg-mate.is-picked[b-zyg9cvz903] {
        background: #f0fbfc;
        border: 1px solid #b8e5eb;
        border-radius: 12px;
        padding: 8px 10px;
    }

.reg-mate-info[b-zyg9cvz903] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.reg-mate-name[b-zyg9cvz903] {
    font-size: 13px;
    font-weight: 700;
}

.reg-mate-role[b-zyg9cvz903] {
    font-size: 11px;
    color: #5b7280;
}

.reg-mate-remove[b-zyg9cvz903] {
    margin-left: auto;
    background: transparent;
    border: 0;
    font-size: 20px;
    color: #94a3ad;
    cursor: pointer;
    line-height: 1;
}

    .reg-mate-remove:hover[b-zyg9cvz903] {
        color: #dc3545;
    }

/* Search — input only (no outer border on the row) */
.reg-mate-search[b-zyg9cvz903] {
    flex: 1;
    position: relative;
    min-width: 0;
}

    .reg-mate-search .form-control[b-zyg9cvz903] {
        width: 100%;
        box-sizing: border-box;
        font: inherit;
        font-size: 15px;
        color: #0f2a36;
        background: rgba(255, 255, 255, 0.78);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
        border: 0;
        border-radius: 14px;
        outline: none;
        padding: 12px 16px;
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.9),
            inset 0 0 0 1px rgba(10, 111, 125, 0.08),
            0 2px 8px rgba(10, 42, 54, 0.06);
        transition: background 0.18s, box-shadow 0.18s;
    }

        .reg-mate-search .form-control:hover[b-zyg9cvz903] {
            background: rgba(255, 255, 255, 0.92);
            box-shadow:
                inset 0 1px 0 rgba(255, 255, 255, 0.9),
                inset 0 0 0 1px rgba(10, 111, 125, 0.14),
                0 4px 12px rgba(10, 42, 54, 0.08);
        }

        .reg-mate-search .form-control:focus[b-zyg9cvz903] {
            background: #ffffff;
            box-shadow:
                inset 0 1px 0 rgba(255, 255, 255, 0.9),
                0 0 0 1px rgba(14, 165, 183, 0.7),
                0 0 0 4px rgba(14, 165, 183, 0.18);
        }

.reg-search-results[b-zyg9cvz903] {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    max-height: 240px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #d6dce3;
    border-radius: 12px;
    box-shadow: 0 12px 28px rgba(15, 42, 54, 0.16);
    z-index: 10;
    padding: 4px;
}

.reg-search-item[b-zyg9cvz903] {
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    border-radius: 8px;
    padding: 8px 10px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 10px;
    font: inherit;
    color: #0f2a36;
}

    .reg-search-item:hover:not(:disabled)[b-zyg9cvz903] {
        background: #f0fbfc;
    }

    .reg-search-item.is-disabled[b-zyg9cvz903] {
        cursor: not-allowed;
        color: #94a3ad;
    }

.reg-search-name[b-zyg9cvz903] {
    font-weight: 700;
    font-size: 13px;
}

.reg-search-email[b-zyg9cvz903] {
    font-size: 12px;
    color: #5b7280;
    margin-left: 4px;
}

.reg-search-tag[b-zyg9cvz903] {
    margin-left: auto;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #dc3545;
}

.reg-search-empty[b-zyg9cvz903] {
    padding: 10px 12px;
    color: #5b7280;
    font-size: 13px;
}

/* Footer (custom — host dialog's footer is hidden because Buttons=None) */
.reg-dialog-foot[b-zyg9cvz903] {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    margin-top: 6px;
}

/* Button styling now comes from the shared <AppButton> (.app-btn) primitive. */
/* /Components/TournamentSimulationRunDialog.razor.rz.scp.css */
/* Sized by the dialog shell (app-dialog-wide), not by its own content — a min-width here would push the
   body past the shell's max-width and clip the actions off the right edge. */
.tsr[b-zeuerb8ypg] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.tsr-source[b-zeuerb8ypg] {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.tsr-source-name[b-zeuerb8ypg] {
    font-weight: 600;
}

.tsr-source-summary[b-zeuerb8ypg],
.tsr-run-summary[b-zeuerb8ypg] {
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
}

.tsr-controls[b-zeuerb8ypg] {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.tsr-run-count[b-zeuerb8ypg] {
    width: 10rem;
}

.tsr-progress[b-zeuerb8ypg] {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.tsr-status[b-zeuerb8ypg] {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.tsr-status-run[b-zeuerb8ypg] {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.tsr-status-phase[b-zeuerb8ypg],
.tsr-status-name[b-zeuerb8ypg],
.tsr-status-hint[b-zeuerb8ypg] {
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
}

.tsr-runs-title[b-zeuerb8ypg] {
    margin: 0;
}

.tsr-runs[b-zeuerb8ypg] {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 18rem;
    overflow-y: auto;
}

.tsr-run[b-zeuerb8ypg] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.5rem;
}

.tsr-run-main[b-zeuerb8ypg] {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

.tsr-run-name[b-zeuerb8ypg] {
    font-weight: 600;
}

.tsr-run-meta[b-zeuerb8ypg] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.tsr-date[b-zeuerb8ypg] {
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}

.tsr-badge[b-zeuerb8ypg] {
    font-size: 0.75rem;
    font-weight: 700;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
}

.tsr-badge-ok[b-zeuerb8ypg] {
    background: var(--success-bg, #dcfce7);
    color: var(--success, #16a34a);
}

.tsr-badge-warn[b-zeuerb8ypg] {
    background: var(--warning-bg, #fef3c7);
    color: var(--warning, #b45309);
}

.tsr-actions[b-zeuerb8ypg] {
    display: flex;
    justify-content: flex-end;
}
/* /Components/VenueConfiguration.razor.rz.scp.css */
.venue-configuration + .venue-configuration[b-7mr2rrqfi1] {
    margin-top: 12px;
}

[b-7mr2rrqfi1] .child-header {
    align-items: flex-start;
}

[b-7mr2rrqfi1] .child-header > .app-btn--icon {
    margin-top: 6px;
}

.config-name[b-7mr2rrqfi1] {
    flex: 1;
}

.config-courts[b-7mr2rrqfi1] {
    margin-top: 8px;
}

[b-7mr2rrqfi1] .config-courts .form-section-header .app-btn--icon {
    margin-left: 0;
}

.courts-grid[b-7mr2rrqfi1] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(154px, 1fr));
    gap: 14px;
}
/* /Components/VenueForm.razor.rz.scp.css */
/* Court styling lives in Court.razor.css; the courts grid in VenueConfiguration.razor.css */

.map-url-row[b-m2cjkf1cyl] {
    display: flex;
    align-items: stretch;
    gap: 10px;
}

.map-url-row .form-field[b-m2cjkf1cyl] {
    flex: 1;
}

.map-url-link[b-m2cjkf1cyl] {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    border-radius: 10px;
    color: #fff;
    background: linear-gradient(135deg, hsl(var(--hero-hue, 205), 70%, 55%), hsl(calc(var(--hero-hue, 205) + 40), 75%, 65%));
    text-decoration: none;
    transition: filter 120ms ease, transform 120ms ease;
}

.map-url-link:hover[b-m2cjkf1cyl] {
    filter: brightness(1.08);
    transform: translateY(-1px);
}

.venue-form-header[b-m2cjkf1cyl] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

.venue-form-header-text[b-m2cjkf1cyl] {
    flex: 1 1 220px;
    min-width: 0;
}

.venue-form-header-map[b-m2cjkf1cyl] {
    flex: 1 1 220px;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 220px;
}

.venue-form-map[b-m2cjkf1cyl] {
    display: flex;
    justify-content: center;
    animation: venueFormMapAppear-b-m2cjkf1cyl 520ms cubic-bezier(0.22, 1, 0.36, 1) both;
    transform-origin: center top;
}

@keyframes venueFormMapAppear-b-m2cjkf1cyl {
    0% {
        opacity: 0;
        transform: translateY(-12px) scale(0.85);
        filter: blur(6px);
    }
    60% {
        opacity: 1;
        filter: blur(0);
    }
    100% {
        opacity: 1;
        transform: translateY(0) scale(1);
        filter: blur(0);
    }
}

.map-url-loading[b-m2cjkf1cyl] {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
}

@media (prefers-reduced-motion: reduce) {
    .venue-form-map[b-m2cjkf1cyl] {
        animation: none;
    }
}
/* /Controls/ActionsBar.razor.rz.scp.css */
.actions-bar[b-ofvb85hkkg] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 8px 22px rgba(15, 23, 42, 0.06);
}

[b-ofvb85hkkg] .actions-bar-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 20px;
    background: #fff;
    border: 0;
    cursor: pointer;
    color: #0f172a;
    font-family: inherit;
    text-align: left;
    transition: background 0.15s;
}

[b-ofvb85hkkg] .actions-bar-item + .actions-bar-item {
    border-left: 1px solid #e5e7eb;
}

[b-ofvb85hkkg] .actions-bar-item::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    background: transparent;
    transition: background 0.15s;
}

[b-ofvb85hkkg] .actions-bar-item:hover {
    background: #f8fafc;
}

[b-ofvb85hkkg] .actions-bar-item:hover::after {
    background: linear-gradient(90deg, #94a3b8, #334155);
}

[b-ofvb85hkkg] .actions-bar-item-ic {
    flex: none;
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    font-size: 22px;
    color: #475569;
    filter: grayscale(1);
}

[b-ofvb85hkkg] .actions-bar-item-txt {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

[b-ofvb85hkkg] .actions-bar-item-title {
    font-size: 14px;
    font-weight: 800;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

[b-ofvb85hkkg] .actions-bar-item-sub {
    font-size: 11.5px;
    color: #64748b;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (max-width: 640px) {
    .actions-bar[b-ofvb85hkkg] {
        grid-template-columns: 1fr;
    }

    [b-ofvb85hkkg] .actions-bar-item + .actions-bar-item {
        border-left: 0;
        border-top: 1px solid #e5e7eb;
    }
}
/* /Controls/AdminPanel.razor.rz.scp.css */
.admin-panel[b-d5qvl90k1v] {
    margin: 28px 0;
    background: linear-gradient(135deg, #fff8f2 0%, #fff 70%);
    border: 1px solid #ffd9c2;
    border-radius: 14px;
    padding: 16px 20px;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
}

.admin-panel-head[b-d5qvl90k1v] {
    display: flex;
    align-items: center;
    gap: 10px;
}

.admin-panel-actions[b-d5qvl90k1v] {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 12px;
}

.admin-panel-head i[b-d5qvl90k1v] {
    color: #ff7e5f;
    font-size: 18px;
}

.admin-panel-title[b-d5qvl90k1v] {
    margin: 0;
}

.admin-panel-body:not(:empty)[b-d5qvl90k1v] {
    margin-top: 10px;
}
/* /Controls/ContentArea.razor.rz.scp.css */
.content-area[b-ldvv0xmyr3] {
    position: relative;
    padding-top: 0.75rem;
    margin-top: 0.75rem;
}

.content-area-header[b-ldvv0xmyr3] {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0;
    user-select: none;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #64748b;
}

.content-area-header.collapsible[b-ldvv0xmyr3] {
    cursor: pointer;
}

.content-area-header.collapsible:hover[b-ldvv0xmyr3] {
    color: #334155;
}

.content-area-close[b-ldvv0xmyr3] {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: 50%;
    line-height: 1;
    z-index: 2;
}

.content-area-close:hover[b-ldvv0xmyr3],
.content-area-close:focus[b-ldvv0xmyr3] {
    background-color: #dc3545;
    color: #fff;
}
/* /Controls/Countdown.razor.rz.scp.css */
.countdown[b-bujraugijg] {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    padding: 10px 16px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(6px);
    color: inherit;
}

.countdown-upcoming[b-bujraugijg] {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
}

.countdown-label[b-bujraugijg] {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    opacity: 0.85;
}

.countdown-blocks[b-bujraugijg] {
    display: flex;
    align-items: flex-end;
    gap: 6px;
}

.countdown-block[b-bujraugijg] {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 46px;
    padding: 4px 6px;
    border-radius: 8px;
    background: transparent;
}

.countdown-value[b-bujraugijg] {
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    opacity: 0.9;
}

.countdown-unit[b-bujraugijg] {
    margin-top: 4px;
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.7;
}

.countdown-sep[b-bujraugijg] {
    font-size: 18px;
    font-weight: 700;
    opacity: 0.45;
    padding-bottom: 14px;
}

@media (max-width: 540px) {
    .countdown-block[b-bujraugijg] {
        min-width: 40px;
    }
    .countdown-value[b-bujraugijg] {
        font-size: 18px;
    }
}
/* /Controls/DialogCloseButton.razor.rz.scp.css */
.dialog-close-btn[b-tll2relkp0] {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(15, 42, 54, 0.08);
    color: #0f2a36;
    padding: 0;
    cursor: pointer;
    line-height: 1;
    z-index: 2;
    transition: background-color 0.12s, color 0.12s;
}

.dialog-close-btn:hover[b-tll2relkp0],
.dialog-close-btn:focus[b-tll2relkp0] {
    background: rgba(15, 42, 54, 0.18);
    color: #0f2a36;
    outline: none;
}

.dialog-close-btn .bi[b-tll2relkp0] {
    font-size: 1.05rem;
    font-weight: 700;
}
/* /Controls/DialogServiceContainer.razor.rz.scp.css */
.app-dialog[b-jfjy48kxfb] {
    width: 90vw;
    max-width: 520px;
    max-height: 92vh;
    padding: 0;
    border: none;
    border-radius: 16px;
    background: #fff;
    color: #0f2a36;
    box-shadow: 0 24px 60px rgba(15, 42, 54, 0.22);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* A closed <dialog> must not lay out its content: the display:flex above overrides the UA
   dialog:not([open]){display:none}, so without this a not-yet-cleared body would flow into the page
   behind the dialog (absolutely-positioned children like the bracket group legend bleed onto the board). */
.app-dialog:not([open])[b-jfjy48kxfb] {
    display: none;
}

.app-dialog[b-jfjy48kxfb]::backdrop {
    background: rgba(15, 42, 54, 0.45);
    backdrop-filter: blur(2px);
}

.app-dialog.app-dialog-wide[b-jfjy48kxfb] {
    max-width: 680px;
}

.app-dialog.app-dialog-xwide[b-jfjy48kxfb] {
    max-width: 760px;
}

/* The substitute dialog is short and its autocomplete drop-downs are absolutely positioned; letting the
   body scroll would add a second scrollbar alongside each drop-down's own. Keep the body unscrolled so the
   drop-down panel is the only vertical scrollbar. */
.app-dialog.app-dialog-substitute .app-dialog-body[b-jfjy48kxfb] {
    overflow: visible;
}

/* Shrink-to-fit dialog: sizes to its content's natural width instead of a fixed width, up to 95vw — so a
   wide, multi-table body (the pools standings) grows to use the screen while a small body stays compact. */
.app-dialog.app-dialog-fit[b-jfjy48kxfb] {
    width: fit-content;
    max-width: 95vw;
}

/* Near-fullscreen dialog: eagerly claims almost the whole viewport so a large body (e.g. a bracket tree)
   uses the available room before it has to scroll. */
.app-dialog.app-dialog-fullscreen[b-jfjy48kxfb] {
    width: 98vw;
    max-width: none;
    height: 96vh;
    max-height: 96vh;
}

/* Wide growing dialog: claims most of the viewport width (height stays content-driven up to 94vh) so a
   wide, content-rich body — the elimination draw — lays out horizontally instead of stacking tall. */
.app-dialog.app-dialog-grow[b-jfjy48kxfb] {
    width: 98vw;
    max-width: 98vw;
    max-height: 96vh;
}

    .app-dialog.app-dialog-wide .app-dialog-header.info[b-jfjy48kxfb] {
        background: linear-gradient(135deg, var(--brand-accent-warm) 0%, var(--brand-accent) 100%);
    }

.app-dialog-header[b-jfjy48kxfb] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 1rem 1.5rem;
    color: #fff;
    font-weight: 700;
    letter-spacing: 0.01em;
}

.app-dialog-close[b-jfjy48kxfb] {
    margin-left: auto;
    background: transparent;
    border: 0;
    color: #fff;
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
    opacity: 0.85;
    transition: opacity .12s, transform .08s;
}

    .app-dialog-close:hover[b-jfjy48kxfb] {
        opacity: 1;
        transform: scale(1.1);
    }

    .app-dialog-header.info[b-jfjy48kxfb],
    .app-dialog-header.success[b-jfjy48kxfb] {
        background: linear-gradient(135deg, var(--brand-primary) 0%, var(--brand-primary-dark) 100%);
    }

    .app-dialog-header.warning[b-jfjy48kxfb] {
        background: linear-gradient(135deg, var(--brand-accent-warm) 0%, var(--brand-accent) 100%);
    }

    .app-dialog-header.error[b-jfjy48kxfb] {
        background: linear-gradient(135deg, #c2389b 0%, #dc3545 100%);
    }

    .app-dialog-header .bi[b-jfjy48kxfb] {
        font-size: 1.4rem;
        line-height: 1;
    }

.app-dialog-title[b-jfjy48kxfb] {
    margin: 0;
    color: inherit;
}

.app-dialog-body[b-jfjy48kxfb] {
    padding: 1.5rem;
    font-size: 1rem;
    line-height: 1.5;
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
}

.app-dialog-message[b-jfjy48kxfb] {
    margin: 0;
}

.app-dialog-footer[b-jfjy48kxfb] {
    display: flex;
    gap: 0.75rem;
    justify-content: flex-end;
    padding: 0 1.5rem 1.5rem;
}

/* Button styling now comes from the shared <AppButton> (.app-btn) primitive. */

@media (max-width: 540px) {
    .app-dialog[b-jfjy48kxfb] {
        width: 94vw;
    }

    .app-dialog-header[b-jfjy48kxfb],
    .app-dialog-body[b-jfjy48kxfb] {
        padding: 1rem 1.25rem;
    }

    .app-dialog-footer[b-jfjy48kxfb] {
        padding: 0 1.25rem 1.25rem;
    }
}
/* /Controls/FormInputDate.razor.rz.scp.css */
/* Date inputs render their own value/placeholder UI, so the label is always
   pinned to the top — overrides the floating-label behavior in app.css. */
.form-field > label[b-4sh1rsnbg8] {
    top: 9px;
    transform: none;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}
/* /Controls/FormInputEdit.razor.rz.scp.css */
.text-input-display[b-lcn3fdqugv] {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: transparent;
    cursor: pointer;
    transition: border-color 0.12s, background-color 0.12s;
}

.text-input-display:hover[b-lcn3fdqugv] {
    border-color: #d6dce3;
    background: #f5f7fa;
}

.text-input-value[b-lcn3fdqugv] {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    color: #0f2a36;
}

.text-input-value:empty[b-lcn3fdqugv]::before {
    content: "\2014";
    color: #9ca3af;
}

.text-input-placeholder[b-lcn3fdqugv] {
    color: #9ca3af;
    font-style: italic;
    font-weight: 400;
}

.text-input-edit-icon[b-lcn3fdqugv] {
    color: #9ca3af;
    line-height: 1;
    display: inline-flex;
    flex-shrink: 0;
}

.text-input-display:hover .text-input-edit-icon[b-lcn3fdqugv] {
    color: var(--brand-primary-dark);
}

.text-input-textarea[b-lcn3fdqugv] {
    width: 100%;
    box-sizing: border-box;
    resize: none;
    overflow: hidden;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    min-height: 0;
    border: 1px solid #d6dce3;
    border-radius: 8px;
    padding: 8px 12px;
    font: inherit;
    color: #0f2a36;
    background: #fff;
    outline: none;
    transition: border-color 0.12s, box-shadow 0.12s;
}

.text-input-textarea:focus[b-lcn3fdqugv] {
    border-color: rgba(14, 165, 183, 0.7);
    box-shadow: 0 0 0 3px rgba(14, 165, 183, 0.18);
}

.text-input-textarea[b-lcn3fdqugv]::placeholder {
    color: #9ca3af;
    font-style: italic;
    font-weight: 400;
}
/* /Controls/FormInputScore.razor.rz.scp.css */
.fis[b-dcdd9u2vqa] {
    width: 100%;
    height: 46px;
    border: 1.5px solid #e7ebee;
    border-radius: 10px;
    text-align: center;
    font-size: 21px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    color: #0f2a36;
    background: #fafdfe;
    outline: none;
    /* hide the number spinner — the score cells are tap/type only */
    -moz-appearance: textfield;
    appearance: textfield;
}

.fis[b-dcdd9u2vqa]::-webkit-outer-spin-button,
.fis[b-dcdd9u2vqa]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.fis:focus[b-dcdd9u2vqa] {
    border-color: var(--brand-primary);
    background: #fff;
    box-shadow: 0 0 0 3px rgba(14, 165, 183, 0.16);
}

/* Losing side fades to match the live timeline's winner/loser emphasis (no colour fill). */
.fis.is-lose[b-dcdd9u2vqa] {
    color: #9aa0a4;
}

/* Automated cell: the placeholder is a short "it'll be tallied for you" prose hint, not a real value —
   so it reads muted, smaller, and gently pulses to signal it's a live/automatic state, not typed input. */
.fis.is-auto[b-dcdd9u2vqa]::placeholder {
    color: #9aa0a4;
    font-weight: 800;
    font-size: 11px;
    letter-spacing: 0.01em;
    opacity: 1;
    animation: fis-auto-pulse-b-dcdd9u2vqa 1.7s ease-in-out infinite;
}

@keyframes fis-auto-pulse-b-dcdd9u2vqa {
    0%, 100% {
        opacity: 0.4;
    }
    50% {
        opacity: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .fis.is-auto[b-dcdd9u2vqa]::placeholder {
        animation: none;
        opacity: 0.7;
    }
}
/* /Controls/FormInputTextArea.razor.rz.scp.css */
/* Textarea-only overrides; base floating-label styling comes from app.css. */
.form-row[b-w3pc650w83]  .form-control {
    padding-top: 26px;
    resize: none;
    overflow-y: hidden;
}
/* /Controls/InputAutoComplete.razor.rz.scp.css */
.iac[b-u60w8kyvlh] {
    position: relative;
    flex: 1;
    min-width: 0;
}

.iac-input[b-u60w8kyvlh] {
    width: 100%;
    box-sizing: border-box;
    font: inherit;
    font-size: 15px;
    color: #0f2a36;
    background: rgba(255, 255, 255, 0.78);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 0;
    border-radius: 14px;
    outline: none;
    padding: 12px 16px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.9),
        inset 0 0 0 1px rgba(10, 111, 125, 0.08),
        0 2px 8px rgba(10, 42, 54, 0.06);
    transition: background 0.18s, box-shadow 0.18s;
}

    .iac-input:hover[b-u60w8kyvlh] {
        background: rgba(255, 255, 255, 0.92);
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.9),
            inset 0 0 0 1px rgba(10, 111, 125, 0.14),
            0 4px 12px rgba(10, 42, 54, 0.08);
    }

    .iac-input:focus[b-u60w8kyvlh] {
        background: #ffffff;
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.9),
            0 0 0 1px rgba(14, 165, 183, 0.7),
            0 0 0 4px rgba(14, 165, 183, 0.18);
    }

.iac-panel[b-u60w8kyvlh] {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 6px);
    max-height: 240px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #d6dce3;
    border-radius: 12px;
    box-shadow: 0 12px 28px rgba(15, 42, 54, 0.16);
    z-index: 10;
    padding: 4px;
}

.iac-flip .iac-panel[b-u60w8kyvlh] {
    top: auto;
    bottom: calc(100% + 6px);
    box-shadow: 0 -12px 28px rgba(15, 42, 54, 0.16);
}

.iac-item[b-u60w8kyvlh] {
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    border-radius: 8px;
    padding: 8px 10px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 10px;
    font: inherit;
    color: #0f2a36;
}

    .iac-item:hover:not(:disabled)[b-u60w8kyvlh] {
        background: #f0fbfc;
    }

    .iac-item.is-disabled[b-u60w8kyvlh] {
        cursor: not-allowed;
        color: #94a3ad;
    }

.iac-empty[b-u60w8kyvlh] {
    padding: 10px 12px;
    color: #5b7280;
    font-size: 13px;
}

.iac-clearable .form-control[b-u60w8kyvlh] {
    padding-right: 40px;
}

.iac-clear[b-u60w8kyvlh] {
    position: absolute;
    right: 10px;
    top: 50%;
    transform: translateY(-50%);
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(15, 42, 54, 0.06);
    color: #5b7280;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    transition: background 0.12s, color 0.12s, transform 0.08s;
}

.iac-clear:hover[b-u60w8kyvlh] {
    background: rgba(220, 38, 38, 0.14);
    color: #dc2626;
}

.iac-clear:active[b-u60w8kyvlh] {
    transform: translateY(-50%) scale(0.92);
}
/* /Controls/InputDropdown.razor.rz.scp.css */
/* Base .form-row / .form-field / .form-control / :required / :focus / .invalid
   / label transforms / validation-message all come from app.css. The dropdown-
   specific overlay (appearance:none + chevron + placeholder option styling)
   also lives in app.css under `.form-row select.form-control`. */

/* In legacy mode, the <button> + <selectedcontent> children are
   ignored by the browser — hide defensively in case any UA renders them. */
.form-row .form-control > .select-trigger[b-k0x2wflvc7] {
    display: none;
}

/* Modern customizable-select (Chromium 134+, progressive enhancement).
   Non-supporting browsers keep the native fallback. */
@supports (appearance: base-select) {
    .form-row .form-control[b-k0x2wflvc7],
    .form-row .form-control[b-k0x2wflvc7]::picker(select) {
        appearance: base-select;
    }

    .form-row .form-control[b-k0x2wflvc7] {
        /* Re-apply the trigger look — base-select disables the legacy chrome,
           and the trigger is now the inner <button>. */
        background-image: none;
        padding: 0;
        display: block;
        min-height: 0;
        height: auto;
    }

    .form-row .form-control[b-k0x2wflvc7]::picker-icon {
        display: none;
    }

    .form-row .form-control > .select-trigger[b-k0x2wflvc7] {
        display: flex;
        align-items: center;
        width: 100%;
        box-sizing: border-box;
        padding: 24px 40px 10px 16px;
        border: none;
        background: transparent;
        font: inherit;
        color: inherit;
        text-align: left;
        cursor: pointer;
        position: relative;
        min-height: 56px;
    }

    .form-row .form-control > .select-trigger selectedcontent[b-k0x2wflvc7] {
        flex: 1;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .form-row .form-control > .select-trigger .picker-icon[b-k0x2wflvc7] {
        position: absolute;
        right: 16px;
        top: 50%;
        width: 12px;
        height: 8px;
        transform: translateY(-50%);
        background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5L6 6.5L11 1.5' stroke='%230a6f7d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>") no-repeat center / contain;
        transition: transform 0.2s;
    }

    .form-row .form-control:open > .select-trigger .picker-icon[b-k0x2wflvc7] {
        transform: translateY(-50%) rotate(180deg);
    }

    .form-row .form-control[b-k0x2wflvc7]::picker(select) {
        margin-top: 6px;
        padding: 6px;
        border: none;
        border-radius: 14px;
        background: rgba(255, 255, 255, 0.96);
        backdrop-filter: blur(14px);
        -webkit-backdrop-filter: blur(14px);
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.9),
            inset 0 0 0 1px rgba(10, 111, 125, 0.1),
            0 12px 32px rgba(10, 42, 54, 0.18);
        max-height: 320px;
        overflow-y: auto;
        opacity: 0;
        transform: translateY(-4px);
        transition: opacity 0.12s ease-out, transform 0.12s ease-out, display 0.12s allow-discrete;
    }

    .form-row .form-control[b-k0x2wflvc7]::picker(select):popover-open {
        opacity: 1;
        transform: translateY(0);
    }

    @starting-style {
        .form-row .form-control[b-k0x2wflvc7]::picker(select):popover-open {
            opacity: 0;
            transform: translateY(-4px);
        }
    }

    .form-row .form-control option[b-k0x2wflvc7] {
        padding: 10px 14px;
        border-radius: 10px;
        font-size: 15px;
        color: #0f2a36;
        background: transparent;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 8px;
    }

    .form-row .form-control option:hover[b-k0x2wflvc7] {
        background: rgba(14, 165, 183, 0.12);
        color: var(--brand-primary-dark);
    }

    .form-row .form-control option:checked[b-k0x2wflvc7] {
        background: rgba(14, 165, 183, 0.18);
        color: var(--brand-primary-dark);
        font-weight: 600;
    }

    .form-row .form-control option[b-k0x2wflvc7]::checkmark {
        content: "✓";
        color: var(--brand-primary-dark);
        font-weight: 700;
        order: 1;
        margin-left: auto;
    }

    .form-row .form-control option:not(:checked)[b-k0x2wflvc7]::checkmark {
        visibility: hidden;
    }

    .form-row .form-control option.placeholder-option[b-k0x2wflvc7] {
        color: #94a3b8;
        font-style: italic;
    }
}
/* /Controls/NotificationCenter.razor.rz.scp.css */
/* Bottom-right notification layer, anchored by its bottom edge so tiles flow upward as they arrive. The
   layer is click-through — only the slab takes pointer events — so it never blocks the page underneath.
   z-index sits above the page and the nav-bar (10) but below the modal dialog layer (1050), so opening a
   dialog from a tile covers the stack rather than fighting it.

   --notif-bottom (app.css) lifts the layer clear of a page's status bar where one is mounted; the 60dvh
   cap is what keeps the slab away from the top navigation bar, since anchored near the bottom edge it can
   only ever reach ~40% down the viewport. */
.notif-layer[b-8zsf6sq3nj] {
    position: fixed;
    right: 18px;
    bottom: var(--notif-bottom, 18px);
    z-index: 900;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    width: 200px;
    max-width: calc(100vw - 36px);
    max-height: 60dvh;
    pointer-events: none;
}

/* The same frosted dark-grey slab as the list pages' search footer (--surface-frost-*, app.css): the board
   shows through it, blurred, so the stack never blanks out what it covers. Two rows — the header keeps its
   height while the column below collapses to nothing. */
.notif-panel[b-8zsf6sq3nj] {
    pointer-events: auto;
    display: grid;
    grid-template-rows: auto 1fr;
    max-height: 100%;
    overflow: hidden;
    border-radius: 14px;
    border: 1px solid var(--surface-frost-dark-border);
    background: var(--surface-frost-dark);
    color: var(--surface-frost-dark-ink);
    backdrop-filter: var(--surface-frost-blur);
    -webkit-backdrop-filter: var(--surface-frost-blur);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
}

.notif-panel.is-collapsed[b-8zsf6sq3nj] {
    grid-template-rows: auto 0fr;
}

/* Nothing to report — the slab gets out of the way entirely rather than sitting there empty. */
.notif-panel.is-empty[b-8zsf6sq3nj] {
    display: none;
}

.notif-hdr[b-8zsf6sq3nj] {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    border: 0;
    cursor: pointer;
    padding: 9px 12px;
    text-align: left;
    background: rgba(255, 255, 255, 0.06);
    color: inherit;
    font: inherit;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.notif-panel.is-collapsed .notif-hdr[b-8zsf6sq3nj] {
    border-bottom: 0;
}

.notif-hdr-title[b-8zsf6sq3nj] {
    flex: 1;
    min-width: 0;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.7px;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Live count — the one thing that still has to read at a glance while the slab is folded shut. */
.notif-hdr-badge[b-8zsf6sq3nj] {
    background: rgba(255, 255, 255, 0.92);
    color: #1f2937;
    border-radius: 999px;
    min-width: 20px;
    padding: 1px 7px;
    font-size: 10.5px;
    font-weight: 800;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.notif-hdr-chev[b-8zsf6sq3nj] {
    display: flex;
    font-size: 9px;
    color: rgba(255, 255, 255, 0.6);
}

.notif-panel.is-collapsed .notif-hdr-chev[b-8zsf6sq3nj] {
    transform: rotate(-90deg);
}

.notif-wrap[b-8zsf6sq3nj] {
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* Ordinary scrollbar — thin and tinted for the dark slab, but the platform's own control. */
.notif-vp[b-8zsf6sq3nj] {
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.42) transparent;
    padding: 9px;
    min-height: 0;
}

.notif-stack[b-8zsf6sq3nj] {
    display: flex;
    flex-direction: column;
    gap: 9px;
    /* Pins the tiles to the bottom of the viewport while they are fewer than fit; resolves to 0 once they
       overflow, so the column then scrolls normally. */
    margin-top: auto;
}

/* Each tile is a lighter pane cut into the slab, and is itself the click target for the page's action. */
.notif-tile[b-8zsf6sq3nj] {
    position: relative;
    border-radius: 11px;
    padding: 9px 11px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.16);
    animation: notif-rise-b-8zsf6sq3nj 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.1) both;
}

.notif-tile.is-actionable[b-8zsf6sq3nj] {
    cursor: pointer;
}

.notif-tile.is-actionable:hover[b-8zsf6sq3nj] {
    background: rgba(255, 255, 255, 0.18);
    border-color: rgba(255, 255, 255, 0.28);
}

.notif-tile.is-actionable:focus-visible[b-8zsf6sq3nj] {
    outline: 2px solid rgba(255, 255, 255, 0.7);
    outline-offset: -2px;
}

.notif-hd[b-8zsf6sq3nj] {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* White glyph rather than a colour-only dot: the severity has to survive being read at a glance, and in
   greyscale or by anyone who can't separate the hues. */
.notif-icon[b-8zsf6sq3nj] {
    display: flex;
    flex-shrink: 0;
    font-size: 12px;
    color: #fff;
}

/* One line, always: the caption is a short state word ("Unconfirmed" / "Nepotvrdené"), and anything longer
   is ellipsised rather than allowed to wrap the tile's head. */
.notif-title[b-8zsf6sq3nj] {
    flex: 1;
    min-width: 0;
    font-size: 12.5px;
    font-weight: 700;
    color: #fff;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.notif-body[b-8zsf6sq3nj] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.notif-message[b-8zsf6sq3nj] {
    font-size: 11.5px;
    line-height: 1.35;
    color: rgba(243, 244, 246, 0.82);
    /* A narrow tile can't carry a full pair of team names, so it keeps the first lines and ellipsises. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.notif-detail[b-8zsf6sq3nj] {
    font-size: 10.5px;
    font-style: italic;
    line-height: 1.3;
    color: rgba(243, 244, 246, 0.62);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* New tiles are appended at the bottom of the column and slide up into place. */
@keyframes notif-rise-b-8zsf6sq3nj {
    from {
        opacity: 0;
        transform: translateY(22px) scale(0.96);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .notif-tile[b-8zsf6sq3nj] {
        animation: none;
    }
}

@media (max-width: 760px) {
    .notif-layer[b-8zsf6sq3nj] {
        right: 12px;
    }
}
/* /Controls/PageSidePanel.razor.rz.scp.css */
/* Overlay anchored over the host's content region, holding only the panel. Absolute (not fixed) so it
   stays inside the page content below the app chrome — the host element it sits in must establish a
   positioning context (position: relative). pointer-events:none lets clicks/scroll pass straight
   through to the content behind everywhere except the panel itself (which re-enables them), so the
   page stays interactive while the panel is open. */
.side-panel-root[b-a1dyvmz7sh] {
    position: absolute;
    inset: 0;
    z-index: 1200;
    pointer-events: none;
}

/* Wide screens: a full-height drawer pinned to one edge. The Side modifier on the root picks the
   edge (and its matching slide-in direction). */
.side-panel[b-a1dyvmz7sh] {
    position: absolute;
    top: 0;
    bottom: 0;
    width: min(340px, 86vw);
    display: flex;
    flex-direction: column;
    background: #fff;
    box-shadow: 0 12px 40px rgba(10, 42, 54, 0.22), 0 0 0 1px rgba(10, 42, 54, 0.06);
    pointer-events: auto;
}

.side-panel-left .side-panel[b-a1dyvmz7sh] {
    left: 0;
    animation: side-panel-in-left-b-a1dyvmz7sh 0.22s ease-out;
}

.side-panel-right .side-panel[b-a1dyvmz7sh] {
    right: 0;
    animation: side-panel-in-right-b-a1dyvmz7sh 0.22s ease-out;
}

/* The header echoes the timeline's hour-tick header strip (.tl-ghead): same fill + divider. */
.side-panel-head[b-a1dyvmz7sh] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 10px 10px 16px;
    background: #eef3f4;
    border-bottom: 1px solid #e7ebee;
}

/* Compact panel chrome: the only deviation from the global h3 is the smaller
   size, so the header row stays one line high. */
.side-panel-title[b-a1dyvmz7sh] {
    flex: 1;
    min-width: 0;
    margin: 0;
    font-size: 14px;
    font-weight: 800;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Inline (flex-row) close button so it stays vertically centred against the title — unlike the
   absolutely-corner-pinned DialogCloseButton, which is meant for free-standing dialog panels. */
.side-panel-close[b-a1dyvmz7sh] {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(15, 42, 54, 0.08);
    color: #0f2a36;
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.12s, color 0.12s;
}

.side-panel-close:hover[b-a1dyvmz7sh],
.side-panel-close:focus-visible[b-a1dyvmz7sh] {
    background: rgba(15, 42, 54, 0.18);
    outline: none;
}

.side-panel-body[b-a1dyvmz7sh] {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 14px 16px;
}

@keyframes side-panel-in-left-b-a1dyvmz7sh {
    from {
        transform: translateX(-100%);
    }

    to {
        transform: translateX(0);
    }
}

@keyframes side-panel-in-right-b-a1dyvmz7sh {
    from {
        transform: translateX(100%);
    }

    to {
        transform: translateX(0);
    }
}

/* Portrait (taller than wide): a bottom sheet, full width, sliding up from the bottom with rounded
   top corners — regardless of the wide-screen Side. `orientation: portrait` matches whenever the
   viewport height is >= its width, so it's a pure-CSS height-greater-than-width test. */
@media (orientation: portrait) {
    .side-panel-left .side-panel[b-a1dyvmz7sh],
    .side-panel-right .side-panel[b-a1dyvmz7sh] {
        top: auto;
        right: 0;
        left: 0;
        width: auto;
        max-height: 72vh;
        border-radius: 16px 16px 0 0;
        animation: side-panel-in-bottom-b-a1dyvmz7sh 0.22s ease-out;
    }

    @keyframes side-panel-in-bottom-b-a1dyvmz7sh {
        from {
            transform: translateY(100%);
        }

        to {
            transform: translateY(0);
        }
    }
}
/* /Controls/PodiumFigure.razor.rz.scp.css */
/* Illustrated podium athlete. The figure is sized by the caller (width on .pf); everything inside is
   proportional, so the same component works at hero size on the podium and small anywhere else. */
.pf[b-op32onswmy] {
    position: relative;
    display: block;
    flex: 0 0 auto;
    line-height: 0;
}

.pf-fig[b-op32onswmy] {
    display: block;
    width: 100%;
    height: auto;
}

/* Limbs are stroked skin-coloured lines with round caps standing in for hands and feet. */
.pf-limb[b-op32onswmy] {
    fill: none;
    stroke: var(--pf-skin, #f0c49b);
    stroke-width: 7;
    stroke-linecap: round;
}

.pf-kit[b-op32onswmy] {
    fill: var(--pf-kit, #8fa0b0);
}

.pf-shorts[b-op32onswmy] {
    fill: var(--pf-kit-d, #5d6a76);
}

.pf-skin[b-op32onswmy] {
    fill: var(--pf-skin, #f0c49b);
}

.pf-hair[b-op32onswmy] {
    fill: var(--pf-hair, #2a1d16);
}

/* The brand mark (a trophy with the volleyball cut out of it) used as a mask over a gold fill, so the
   shape comes from the real asset rather than a copy of its path data. It deliberately overflows the top
   of the figure's box — the hands of the CupRaised pose meet its base. */
.pf-cup[b-op32onswmy] {
    position: absolute;
    left: 30.5%;
    top: -5%;
    width: 39%;
    aspect-ratio: 1 / 1;
    background: linear-gradient(180deg, #fff4cf 0%, #f5d24e 50%, #b5860b 100%);
    -webkit-mask: url(/brand-logo.svg) center / contain no-repeat;
    mask: url(/brand-logo.svg) center / contain no-repeat;
    filter: drop-shadow(0 0 7px rgba(253, 230, 138, 0.65));
}
/* /Controls/QuickGridRowExpanderCell.razor.rz.scp.css */
/* The disclosure control itself. Sized to sit on one grid line without stretching the row, so a closed
   grid looks exactly like a plain one with a narrow leading column. */
.qg-row-expand[b-y650v2axku] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid #dbe3e8;
    border-radius: 8px;
    background: #fff;
    color: #5b7280;
    cursor: pointer;
    transition: background-color 0.12s, color 0.12s, border-color 0.12s;
}

    .qg-row-expand:hover[b-y650v2axku] {
        background: #eef4f6;
        color: var(--brand-primary-dark);
        border-color: var(--brand-primary);
    }

    .qg-row-expand:focus-visible[b-y650v2axku] {
        outline: 2px solid var(--brand-primary);
        outline-offset: 1px;
    }

/* A 6px chevron drawn from two borders (the same trick as the grid's sort arrow, so it takes currentColor
   and stays crisp at any zoom): points right when the row is closed, down when it is open. */
.qg-row-expand-chevron[b-y650v2axku] {
    width: 6px;
    height: 6px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    border-radius: 1px;
    transform: rotate(-45deg) translate(-1px, -1px);
    transition: transform 0.12s;
}

.qg-row-expand[aria-expanded="true"] .qg-row-expand-chevron[b-y650v2axku] {
    transform: rotate(45deg) translate(-1px, -1px);
}

@media (prefers-reduced-motion: reduce) {
    .qg-row-expand[b-y650v2axku],
    .qg-row-expand-chevron[b-y650v2axku] {
        transition: none;
    }
}
/* /Controls/RuntimeInfo.razor.rz.scp.css */
.app-version[b-ffew78xmyc] {
    font-size: 0.68rem;
    color: rgba(255, 255, 255, 0.5);
    letter-spacing: 0.03em;
    white-space: nowrap;
    margin-left: 10px;
    align-self: baseline;
    font-weight: 100;
}
/* /Controls/SimulationIndicator.razor.rz.scp.css */
/* Amber "simulation" chip — legible on both the dark venue bar and the white
   compact "paper" bar (a light amber fill with dark amber text/border reads on
   either background, where the old white-on-white was invisible on the compact bar). */
.sim-indicator[b-m6cu07q01w] {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 12px;
    border-radius: 999px;
    background: #fef3c7;
    border: 1px solid #f5c451;
    color: #854d0e;
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
}

.sim-indicator-dot[b-m6cu07q01w] {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #d97706;
    box-shadow: 0 0 0 0 rgba(217, 119, 6, 0.6);
    animation: sim-indicator-pulse-b-m6cu07q01w 1.8s ease-out infinite;
}

.sim-indicator-label[b-m6cu07q01w] {
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.sim-indicator-time[b-m6cu07q01w] {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: #a16207;
}

@keyframes sim-indicator-pulse-b-m6cu07q01w {
    0% {
        box-shadow: 0 0 0 0 rgba(217, 119, 6, 0.6);
    }
    70% {
        box-shadow: 0 0 0 7px rgba(217, 119, 6, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(217, 119, 6, 0);
    }
}

/* Respect reduced-motion: hold the simulation dot steady, no outgoing wave. */
@media (prefers-reduced-motion: reduce) {
    .sim-indicator-dot[b-m6cu07q01w] {
        animation: none;
    }
}
/* /Controls/SplitButton.razor.rz.scp.css */
/* The container draws the outer pill (border + rounded edges) and clips the parts to it; each part
   (SplitButtonPart) paints its own fill, ink and left divider. */
.split-btn[b-tdcarjy4bt] {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--border-color, #d8e1ea);
    border-radius: 999px;
    overflow: hidden;
    background: #fff;
}

/* The outer border tracks the active style's brand token (filled or outline), matching the app's
   .btn-primary / .btn-secondary palette rather than a hard-coded literal. */
.split-btn-c-primary[b-tdcarjy4bt],
.split-btn-c-primary-outline[b-tdcarjy4bt] {
    border-color: var(--brand-primary, #0ea5b7);
}

.split-btn-c-secondary[b-tdcarjy4bt],
.split-btn-c-secondary-outline[b-tdcarjy4bt] {
    border-color: var(--brand-accent-warm, #ff7e5f);
}

.split-btn-c-neutral-outline[b-tdcarjy4bt] {
    border-color: var(--btn-neutral, #74838f);
}

/* Selected category pill: light flat tonal fill with its own muted border (see --split-neutral-* in
   app.css) rather than the dark --gradient-neutral. */
.split-btn-c-neutral[b-tdcarjy4bt] {
    border-color: var(--split-neutral-border, #dadfe4);
}

/* Filled styles paint one continuous gradient across the whole pill; the parts sit transparent on top
   so the gradient reads as a single unbroken sweep rather than per-segment repeats. */
.split-btn-c-primary[b-tdcarjy4bt] {
    background: var(--gradient-primary);
}

.split-btn-c-secondary[b-tdcarjy4bt] {
    background: var(--gradient-secondary);
}

.split-btn-c-neutral[b-tdcarjy4bt] {
    background: var(--split-neutral-fill, #eceff2);
}
/* /Controls/SplitButtonPart.razor.rz.scp.css */
.split-btn-part[b-ucz2juimas] {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    border: 0;
    background: transparent;
    font-size: 0.85rem;
    font-weight: 600;
    padding: 0.35rem 0.7rem;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, filter 0.15s;
}

/* Icon-only parts (e.g. the move arrows) read as compact square buttons. */
.split-btn-part.split-btn-icon[b-ucz2juimas] {
    padding: 0.35rem;
    min-width: 26px;
}

.split-btn-part i[b-ucz2juimas] {
    font-size: 12px;
}

/* Thin divider before every part but the first, drawn as an inset overlay so it sits 2px clear of the
   top/bottom edges rather than spanning the full height. The colour is refined per style below. */
.split-btn-part:not(:first-child)[b-ucz2juimas]::before {
    content: "";
    position: absolute;
    left: 0;
    top: 2px;
    bottom: 2px;
    width: 1px;
    background: var(--border-color, #d8e1ea);
}

/* Disabled fades only the foreground (see per-variant colours below) — the fill stays put so it never
   reads as highlighted. */
.split-btn-part:disabled[b-ucz2juimas] {
    cursor: default;
}

/* The fill (Primary) and accent (Secondary) colours mirror the app's .btn-primary / .btn-secondary
   tokens rather than re-defining literals. */
.split-btn-part[b-ucz2juimas] {
    --split-btn-primary: var(--brand-primary, #0ea5b7);
    --split-btn-secondary: var(--brand-accent-warm, #ff7e5f);
    --split-btn-neutral: var(--btn-neutral, #74838f);
}

/* ── Filled variants ─────────────────────────────────────────────── */
/* Filled parts stay transparent so the container's continuous gradient shows through unbroken; they only
   carry white ink, a white-translucent divider, and a hover overlay that lifts the single hovered
   segment. */
.split-btn-primary[b-ucz2juimas],
.split-btn-secondary[b-ucz2juimas] {
    color: #fff;
}

.split-btn-primary:not(:first-child)[b-ucz2juimas]::before,
.split-btn-secondary:not(:first-child)[b-ucz2juimas]::before {
    background: rgba(255, 255, 255, 0.25);
}

.split-btn-primary:hover:not(:disabled)[b-ucz2juimas],
.split-btn-secondary:hover:not(:disabled)[b-ucz2juimas] {
    background: rgba(255, 255, 255, 0.15);
}

.split-btn-primary:disabled[b-ucz2juimas],
.split-btn-secondary:disabled[b-ucz2juimas] {
    color: rgba(255, 255, 255, 0.45);
}

/* ── Neutral filled — LIGHT flat fill, so it carries dark slate ink and a darkening hover overlay
   (unlike the white-on-dark primary/secondary fills above). The chevron icon parts read a touch lighter
   than the label. */
.split-btn-neutral[b-ucz2juimas] {
    color: var(--split-neutral-ink, #4a5760);
}

.split-btn-neutral.split-btn-icon[b-ucz2juimas] {
    color: #8090a0;
}

.split-btn-neutral:not(:first-child)[b-ucz2juimas]::before {
    background: var(--split-neutral-divider, #d6dce2);
}

.split-btn-neutral:hover:not(:disabled)[b-ucz2juimas] {
    background: rgba(74, 87, 96, 0.09);
}

.split-btn-neutral.split-btn-icon:hover:not(:disabled)[b-ucz2juimas] {
    color: var(--split-neutral-ink, #4a5760);
}

.split-btn-neutral:disabled[b-ucz2juimas] {
    color: #aab3bb;
}

/* ── Outline variants ────────────────────────────────────────────── */
.split-btn-primary-outline[b-ucz2juimas] {
    color: var(--split-btn-primary);
}

.split-btn-secondary-outline[b-ucz2juimas] {
    color: var(--split-btn-secondary);
}

.split-btn-neutral-outline[b-ucz2juimas] {
    color: var(--split-btn-neutral);
}

.split-btn-primary-outline:not(:first-child)[b-ucz2juimas]::before {
    background: color-mix(in srgb, var(--split-btn-primary) 35%, transparent);
}

.split-btn-secondary-outline:not(:first-child)[b-ucz2juimas]::before {
    background: color-mix(in srgb, var(--split-btn-secondary) 35%, transparent);
}

.split-btn-neutral-outline:not(:first-child)[b-ucz2juimas]::before {
    background: color-mix(in srgb, var(--split-btn-neutral) 35%, transparent);
}

.split-btn-primary-outline:hover:not(:disabled)[b-ucz2juimas] {
    background: color-mix(in srgb, var(--split-btn-primary) 10%, transparent);
    color: var(--split-btn-primary);
}

.split-btn-secondary-outline:hover:not(:disabled)[b-ucz2juimas] {
    background: color-mix(in srgb, var(--split-btn-secondary) 12%, transparent);
    color: var(--split-btn-secondary);
}

.split-btn-neutral-outline:hover:not(:disabled)[b-ucz2juimas] {
    background: color-mix(in srgb, var(--split-btn-neutral) 12%, transparent);
    color: var(--split-btn-neutral);
}

.split-btn-primary-outline:disabled[b-ucz2juimas] {
    color: color-mix(in srgb, var(--split-btn-primary) 40%, transparent);
}

.split-btn-secondary-outline:disabled[b-ucz2juimas] {
    color: color-mix(in srgb, var(--split-btn-secondary) 40%, transparent);
}

.split-btn-neutral-outline:disabled[b-ucz2juimas] {
    color: color-mix(in srgb, var(--split-btn-neutral) 40%, transparent);
}
/* /Controls/StatusBar.razor.rz.scp.css */
/* ── Status bar ───────────────────────────────────────────────────────────
   A flex sibling parked at the bottom of a viewport-locked page (the
   .app-scroll-region takes the remaining space and scrolls, so the bar stays put without
   position: sticky). It bleeds edge-to-edge — negative inline margins cancel
   the layout's horizontal content padding (--content-pad-x, set on .content) —
   and casts a soft shade up over the scrolling content. Height is constant
   until the chevron expands it. */
/* --status-bar-height is a shared token (app.css): overlays that have to clear this bar key off the
   same number, so the height is declared once rather than in each of them. */
.status-bar[b-sq3c6cexhb] {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: stretch;
    margin-inline: calc(-1 * var(--content-pad-x, 28px));
    min-height: var(--status-bar-height);
    background: #fff;
    border-top: 1px solid #e7ebee;
    box-shadow: 0 -2px 14px rgba(15, 42, 54, 0.08);
}

/* The single-row track. It never wraps while collapsed: items shrink (see the
   item rules) and, once they bottom out, the row overflows and is clipped — the
   right-edge fade (applied only when .is-overflowing) hints at the hidden
   items, which the chevron reveals. */
.status-bar-track[b-sq3c6cexhb] {
    flex: 1;
    min-width: 0;
    height: var(--status-bar-height);
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 26px;
    padding: 10px 22px;
    overflow: hidden;
}

.status-bar.is-overflowing:not(.is-expanded) .status-bar-track[b-sq3c6cexhb] {
    -webkit-mask: linear-gradient(to right, #000 calc(100% - 28px), transparent);
    mask: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}

/* Expanded: the bar grows and the row wraps so every item is visible. */
.status-bar.is-expanded .status-bar-track[b-sq3c6cexhb] {
    height: auto;
    flex-wrap: wrap;
    row-gap: 16px;
    padding-block: 14px;
    overflow: visible;
}

/* ── Items ───────────────────────────────────────────────────────────────── */
[b-sq3c6cexhb] .status-bar-item {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    /* Floor each item at its content width so the nowrap label/value can never
       shrink small enough to spill over a neighbour. Once an item no longer
       fits, the row overflows and the item is clipped (then revealed by the
       chevron) instead of overlapping the one beside it. */
    min-width: max-content;
    flex: 0 1 auto;
}

[b-sq3c6cexhb] .status-bar-item.is-grow {
    flex: 1 1 auto;
    min-width: 180px;
}

/* Thin separator centred in the 26px gap between adjacent items. Hidden once
   the row wraps so it never floats between stacked rows. */
[b-sq3c6cexhb] .status-bar-item + .status-bar-item::before {
    content: "";
    position: absolute;
    left: -13px;
    top: 50%;
    transform: translateY(-50%);
    width: 1px;
    height: 26px;
    background: #e7ebee;
}

.status-bar.is-expanded[b-sq3c6cexhb]  .status-bar-item + .status-bar-item::before {
    display: none;
}

[b-sq3c6cexhb] .status-bar-item-label {
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #5b7280;
    white-space: nowrap;
}

[b-sq3c6cexhb] .status-bar-item-value {
    font-size: 15px;
    font-weight: 800;
    color: #0f2a36;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

[b-sq3c6cexhb] .status-bar-item-value.ok {
    color: #15803d;
}

[b-sq3c6cexhb] .status-bar-item-value.warn {
    color: #b45309;
}

/* ── Chevron toggle ────────────────────────────────────────────────────────
   Appears only when items overflow (or while expanded). It hangs off the right
   edge above the fade and rotates when open. */
.status-bar-toggle[b-sq3c6cexhb] {
    flex: 0 0 auto;
    align-self: stretch;
    width: 52px;
    border: 0;
    border-left: 1px solid #e7ebee;
    background: #fff;
    color: #5b7280;
    cursor: pointer;
    display: grid;
    place-items: center;
    transition: background 0.15s, color 0.15s;
}

.status-bar-toggle:hover[b-sq3c6cexhb] {
    background: #f8fafc;
    color: #0f2a36;
}

.status-bar-chevron[b-sq3c6cexhb] {
    font-size: 16px;
    line-height: 1;
    transition: transform 0.18s;
}

.status-bar.is-expanded .status-bar-chevron[b-sq3c6cexhb] {
    transform: rotate(180deg);
}
/* /Controls/VenueMap.razor.rz.scp.css */
.venue-map[b-t6zjndqglh] {
    display: block;
    width: 100%;
    max-width: 280px;
}

.venue-map svg[b-t6zjndqglh] {
    width: 100%;
    height: auto;
    display: block;
    overflow: visible;
}

.venue-map-loading[b-t6zjndqglh] {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 5 / 3;
}

.venue-map-country[b-t6zjndqglh] {
    fill: rgba(255, 255, 255, 0.18);
    stroke: rgba(255, 255, 255, 0.85);
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
    vector-effect: non-scaling-stroke;
}

.venue-map-pin-halo[b-t6zjndqglh] {
    fill: rgba(255, 255, 255, 0.22);
    transform-origin: center;
    transform-box: fill-box;
}

.venue-map-pin-wave[b-t6zjndqglh] {
    fill: none;
    stroke: rgba(255, 255, 255, 0.85);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
    transform-origin: center;
    transform-box: fill-box;
    animation: venueMapPinWave-b-t6zjndqglh 3s ease-out infinite;
    will-change: transform, opacity;
}

.venue-map-pin[b-t6zjndqglh] {
    fill: #e8362f;
    stroke: rgba(0, 0, 0, 0.3);
    stroke-width: 1.5;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

.venue-map-pin-eye[b-t6zjndqglh] {
    fill: #ffffff;
}

.venue-map-link[b-t6zjndqglh] {
    cursor: pointer;
    text-decoration: none;
}

.venue-map[b-t6zjndqglh]  .venue-map-label {
    fill: #ffffff;
    font-family: inherit;
    font-weight: 600;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55));
}

.venue-map-link:hover[b-t6zjndqglh]  .venue-map-label {
    fill: var(--brand-accent-warm);
}

@keyframes venueMapPinWave-b-t6zjndqglh {
    0% { opacity: 0.7; transform: scale(0.3); }
    80% { opacity: 0; transform: scale(2.4); }
    100% { opacity: 0; transform: scale(2.4); }
}

@media (prefers-reduced-motion: reduce) {
    .venue-map-pin-wave[b-t6zjndqglh] { animation: none; opacity: 0; }
}
/* /Layout/MainLayout.razor.rz.scp.css */
.page[b-83xijclryb] {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    width: fit-content;
    min-width: 100%;
    /* Never grow past the viewport: fit-content would otherwise let a wide child
       (e.g. a QuickGrid table) stretch the whole shell and give the page a
       horizontal scrollbar. Capped here so wide content scrolls locally within its
       own overflow container instead (the app's pattern — see TournamentLiveTimeLine). */
    max-width: 100%;
    /* Approximate height of TopNav. Used to offset the hero's sun so it lines
       up with the nav-bar sun and looks like a single continuous orb. */
    --nav-bar-height: 62px;
}

/* Slim sticky bar that carries only TopNav. Shares the venue gradient colors
   with the hero so at rest the two visually merge into one cohesive header.
   Once the user scrolls, the hero (with its title/subtitle/CTAs and wave) scrolls
   away and only this slim bar remains pinned. */
.nav-bar[b-83xijclryb] {
    position: sticky;
    top: 0;
    z-index: 10;
    --venue-bg: #ffb37a;
    --venue-accent: var(--brand-accent);
    --venue-fg: #fff;
    color: #fff;
}

/* Compact "paper" header (tournament live / schedule / groups / bracket): drop the
   venue-colour wash for a calm white bar so it stops competing with the colourful
   in-page controls. Venue identity is replaced by the brand: a coral top stripe and
   the coral-tinted brand mark (see TopNav.razor.css). */
.nav-bar.compact[b-83xijclryb] {
    background: #fff;
    border-bottom: 1px solid #e6ebef;
    box-shadow: 0 2px 12px rgba(15, 22, 32, 0.06);
}

.nav-bar.compact .nav-bar-bg[b-83xijclryb] {
    display: none;
}

.nav-bar.compact[b-83xijclryb]::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--brand-accent), var(--brand-accent-warm));
}

/* Same gradient definition as .hero-bg. Both use background-attachment: fixed
   so they share viewport coordinates — the gradient stops align across the
   seam and the nav-bar + hero render as one continuous wash at rest. */
.nav-bar-bg[b-83xijclryb] {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    /* Clip the embedded sun to the nav-bar's bounds so it can't draw on top of
       the hero content (or, when scrolled, on top of page cards). The hero's
       own sun continues the visual seamlessly below. */
    overflow: hidden;
    background:
        radial-gradient(ellipse at top right, rgba(255, 255, 255, 0.18), transparent 55%),
        linear-gradient(135deg,
            var(--venue-bg) 0%,
            var(--venue-accent) 60%,
            color-mix(in oklab, var(--venue-accent) 70%, black) 100%);
    background-attachment: fixed, fixed;
}

.hero[b-83xijclryb] {
    position: relative;
    z-index: 5;
    filter: drop-shadow(0 8px 10px rgba(0, 0, 0, 0.25));
    --venue-bg: #ffb37a;
    --venue-accent: var(--brand-accent);
    --venue-fg: #fff;
    color: #fff;
    /* Reserve exactly the wave's height at the bottom so it sits in dedicated space
       and never overlaps header content, regardless of how short the hero is. */
    padding-bottom: 16px;
}

/* Decorative background + wave mask live on a sibling of TopNav so the mask
   does not clip nav dropdowns that extend past the wave edge. */
.hero-bg[b-83xijclryb] {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(ellipse at top right, rgba(255, 255, 255, 0.18), transparent 55%),
        linear-gradient(135deg,
            var(--venue-bg) 0%,
            var(--venue-accent) 60%,
            color-mix(in oklab, var(--venue-accent) 70%, black) 100%);
    /* Match .nav-bar-bg's fixed attachment so gradient stops align across the seam. */
    background-attachment: fixed, fixed;
    -webkit-mask:
        linear-gradient(#000, #000) top / 100% calc(100% - 16px) no-repeat,
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 16' preserveAspectRatio='none'><path d='M0,0 L1200,0 L1200,8 C1150,2 1050,12 900,6 C600,-4 300,18 0,6 Z' fill='black'/></svg>") bottom / 100% 16px no-repeat;
    mask:
        linear-gradient(#000, #000) top / 100% calc(100% - 16px) no-repeat,
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 16' preserveAspectRatio='none'><path d='M0,0 L1200,0 L1200,8 C1150,2 1050,12 900,6 C600,-4 300,18 0,6 Z' fill='black'/></svg>") bottom / 100% 16px no-repeat;
}

/* Clips the sun glow without clipping floating UI (e.g. nav dropdowns) */
.hero-clip[b-83xijclryb] {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.sun[b-83xijclryb] {
    position: absolute;
    top: -100px;
    right: -80px;
    width: 340px;
    height: 340px;
    border-radius: 50%;
    background: radial-gradient(circle, #ffe7a3 0%, #ffb37a 60%, transparent 72%);
    filter: blur(1px);
    opacity: 0.95;
    pointer-events: none;
}

/* The hero sits below the nav-bar, so its sun must be shifted up by the
   nav-bar height to land at the same viewport coordinates as the nav-bar's
   sun — producing one continuous orb across both regions at rest. */
.hero-clip .sun[b-83xijclryb] {
    top: calc(-100px - var(--nav-bar-height));
}

main[b-83xijclryb] {
    flex: 1;
    /* Allow the flex item to shrink below its content's intrinsic width (flex items
       default to min-width:auto). Without this, a wide child (e.g. a QuickGrid table)
       forces main past the viewport and the page grows a horizontal scrollbar instead
       of the child scrolling locally within its own overflow container. */
    min-width: 0;
    position: relative;
    z-index: 2;
    align-self: stretch;
}

.content[b-83xijclryb] {
    /* Exposed so full-bleed children (e.g. a viewport-locked page's StatusBar)
       can cancel the horizontal padding with a matching negative margin. */
    --content-pad-x: 28px;
    width: 100%;
    padding: 20px var(--content-pad-x) 80px;
    position: relative;
    z-index: 3;
}

#blazor-error-ui[b-83xijclryb] {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss[b-83xijclryb] {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

@media (max-width: 760px) {
    .page[b-83xijclryb] {
        /* TopNav padding grows to 16px top/bottom on mobile (see TopNav.razor.css). */
        --nav-bar-height: 70px;
    }

    .content[b-83xijclryb] {
        --content-pad-x: 18px;
        padding: 20px var(--content-pad-x) 60px;
    }
}
/* /Layout/PageHeader.razor.rz.scp.css */
.page-header[b-fqa795f5gf] {
    position: relative;
    z-index: 2;
    padding: 5px 28px;
    color: #fff;
}

@media (max-width: 760px) {
    .page-header[b-fqa795f5gf] {
        padding: 5px 18px;
    }
}
/* /Layout/TopNav.razor.rz.scp.css */
.top-nav[b-ls742xf6hj] {
    position: relative;
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 32px;
    padding: 12px 32px;
    color: #fff;
}

.brand[b-ls742xf6hj] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'Outfit', 'Manrope', system-ui, sans-serif;
    font-weight: 900;
    font-size: 28px;
    color: #fff;
    text-decoration: none;
}

.brand-text[b-ls742xf6hj] {
    display: inline-flex;
    align-items: baseline;
}

/* The brand mark is drawn as a tintable silhouette: the logo SVG is used as a mask
   and the colour comes from --brand-icon-color (white by default; coral in the
   compact paper header). */
.brand-icon[b-ls742xf6hj] {
    width: 34px;
    height: 34px;
    display: block;
    background-color: var(--brand-icon-color, #fff);
    -webkit-mask: url(/brand-logo.svg) center / contain no-repeat;
    mask: url(/brand-logo.svg) center / contain no-repeat;
}

.brand-name[b-ls742xf6hj] {
    line-height: 1;
}

/* Compact mode: the brand name is swapped for the page title (e.g. the
   tournament name on a full-screen live page). Shrinks (with an ellipsis) so an
   adjacent status pill stays glued after the name; .actions keeps its
   margin-left:auto to push the avatar/hamburger to the far right. */
.nav-title[b-ls742xf6hj] {
    flex: 0 1 auto;
    min-width: 0;
    font-family: 'Outfit', 'Manrope', system-ui, sans-serif;
    font-weight: 800;
    font-size: 19px;
    letter-spacing: -0.01em;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Status pill rendered immediately after the title. Plain/neutral by default
   (e.g. the schedule page's "Schedule"); the .live modifier turns it into the
   red, pulsing "LIVE" pill. */
.nav-badge[b-ls742xf6hj] {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 11px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.12);
    border: 1px solid rgba(255, 255, 255, 0.25);
    color: #fff;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
}

.nav-badge.live[b-ls742xf6hj] {
    background: rgba(220, 38, 38, 0.95);
    border-color: rgba(248, 113, 113, 1);
}

.nav-badge.live[b-ls742xf6hj]::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    animation: nav-badge-pulse-b-ls742xf6hj 1.5s ease-out infinite;
}

@keyframes nav-badge-pulse-b-ls742xf6hj {
    0% {
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    }
    70% {
        box-shadow: 0 0 0 7px rgba(255, 255, 255, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
    }
}

/* "Me today" pill — a shortcut to the signed-in player's own day, shown only while they are playing in a
   running tournament. Deliberately NOT part of the live pill's red family: this is the player's own
   destination, not a state of the tournament, and the two sit side by side on the compact bar. It is set
   apart twice over — by a violet that appears nowhere else in the app, and by a silhouette no other pill
   has: a two-part ticket whose second half carries the court and slot time of their next match, split off
   by a dashed perforation. Both halves render identically on the venue gradient and the white paper bar. */
.nav-myday[b-ls742xf6hj] {
    display: inline-flex;
    align-items: stretch;
    flex: none;
    margin-left: 10px;
    border-radius: 999px;
    overflow: hidden;
    background: linear-gradient(135deg, var(--myday-from), var(--myday-to));
    border: 1px solid rgba(255, 255, 255, 0.5);
    color: #fff;
    text-decoration: none;
    white-space: nowrap;
    box-shadow: 0 5px 18px rgba(79, 70, 229, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.28);
    transition: filter 0.14s ease, box-shadow 0.14s ease, transform 0.14s ease;
}

.nav-myday:hover[b-ls742xf6hj],
.nav-myday:focus-visible[b-ls742xf6hj] {
    color: #fff;
    transform: translateY(-1px);
    filter: brightness(1.1);
    box-shadow: 0 8px 24px rgba(79, 70, 229, 0.58), inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.nav-myday-label[b-ls742xf6hj] {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    font-size: 11.5px;
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* The data half: dashed perforation, tabular figures so the time doesn't jitter as it changes. */
.nav-myday-data[b-ls742xf6hj] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px 6px 11px;
    background: rgba(255, 255, 255, 0.15);
    border-left: 1.5px dashed rgba(255, 255, 255, 0.5);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
}

.nav-myday-court[b-ls742xf6hj] {
    font-size: 10px;
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.66);
}

/* Respect reduced-motion: hold the live-pill dot steady, no outgoing wave. */
@media (prefers-reduced-motion: reduce) {
    .nav-badge.live[b-ls742xf6hj]::before {
        animation: none;
    }
}

.menu[b-ls742xf6hj] {
    display: flex;
    gap: 6px;
    flex: 1;
    justify-content: center;
}

/* Hamburger is hidden on wide screens; revealed by the media query below. */
.hamburger[b-ls742xf6hj] {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    width: 38px;
    height: 38px;
    padding: 0 8px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.12);
    cursor: pointer;
    backdrop-filter: blur(8px);
}

.hamburger span[b-ls742xf6hj] {
    display: block;
    height: 2px;
    background: #fff;
    border-radius: 2px;
    transition: transform 0.18s, opacity 0.18s;
}

.hamburger.active span:nth-child(1)[b-ls742xf6hj] {
    transform: translateY(6px) rotate(45deg);
}

.hamburger.active span:nth-child(2)[b-ls742xf6hj] {
    opacity: 0;
}

.hamburger.active span:nth-child(3)[b-ls742xf6hj] {
    transform: translateY(-6px) rotate(-45deg);
}

/* NavLink renders an <a> as a child component, so it doesn't get the parent's
   scoped attribute — use ::deep to reach into it. */
.menu[b-ls742xf6hj]  .menu-link {
    padding: 9px 16px;
    border-radius: 999px;
    font-weight: 600;
    font-size: 14px;
    color: rgba(255, 255, 255, 0.85);
    text-decoration: none;
    transition: background-color 0.15s, color 0.15s;
}

.menu[b-ls742xf6hj]  .menu-link:hover {
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
}

.menu[b-ls742xf6hj]  .menu-link.active {
    background: #fff;
    color: var(--brand-accent);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
}

.menu-group[b-ls742xf6hj] {
    position: relative;
    display: inline-flex;
}

.menu-group-toggle[b-ls742xf6hj] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: none;
    background: transparent;
    cursor: pointer;
    font-family: inherit;
}

.menu-group-toggle .caret[b-ls742xf6hj] {
    font-size: 10px;
    line-height: 1;
    transition: transform 0.15s;
}

.menu-group.open .menu-group-toggle .caret[b-ls742xf6hj] {
    transform: rotate(180deg);
}

.menu-dropdown[b-ls742xf6hj] {
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    min-width: 180px;
    background: #fff;
    border-radius: 14px;
    padding: 8px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.18);
    display: flex;
    flex-direction: column;
    gap: 2px;
    z-index: 5;
}

.menu-dropdown[b-ls742xf6hj]  .menu-dropdown-link {
    padding: 10px 14px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 600;
    color: #2b2f3a;
    text-decoration: none;
    transition: background-color 0.12s, color 0.12s;
}

.menu-dropdown[b-ls742xf6hj]  .menu-dropdown-link:hover {
    background: rgba(255, 94, 126, 0.1);
    color: var(--brand-accent);
}

.menu-dropdown[b-ls742xf6hj]  .menu-dropdown-link.active {
    background: var(--brand-accent);
    color: #fff;
}

.actions[b-ls742xf6hj] {
    display: flex;
    align-items: center;
    gap: 10px;
}

.lang-group[b-ls742xf6hj] {
    display: inline-flex;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    overflow: hidden;
}

.lang-group-mobile[b-ls742xf6hj] {
    display: none;
}

.lang[b-ls742xf6hj] {
    font-size: 12px;
    font-weight: 700;
    color: #fff;
    padding: 8px 12px;
    cursor: pointer;
    border: none;
    background: transparent;
    transition: background-color 0.15s, color 0.15s;
}

.lang + .lang[b-ls742xf6hj] {
    border-left: 1px solid rgba(255, 255, 255, 0.3);
}

.lang:hover:not(.active):not([disabled])[b-ls742xf6hj] {
    background: rgba(255, 255, 255, 0.15);
}

.lang.active[b-ls742xf6hj] {
    background: rgba(255, 255, 255, 0.22);
    color: #fff;
    cursor: default;
}

.avatar[b-ls742xf6hj] {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: #fff;
    color: var(--brand-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    font-size: 13px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
    text-decoration: none;
}

.avatar-group[b-ls742xf6hj] {
    position: relative;
}

.avatar-toggle[b-ls742xf6hj] {
    border: none;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
}

/* Signed-in avatar keeps the white circle; the initials take the user's chosen hue (grey when none). */
.avatar-hue[b-ls742xf6hj] {
    color: var(--avatar-fg, var(--brand-accent));
}

.menu-dropdown-right[b-ls742xf6hj] {
    left: auto;
    right: 0;
    transform: none;
}

.logout-form[b-ls742xf6hj] {
    margin: 0;
}

.menu-dropdown-button[b-ls742xf6hj] {
    display: block;
    width: 100%;
    text-align: left;
    border: none;
    background: transparent;
    cursor: pointer;
    font-family: inherit;
    padding: 10px 14px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 600;
    color: #2b2f3a;
    transition: background-color 0.12s, color 0.12s;
}

.menu-dropdown-button:hover[b-ls742xf6hj] {
    background: rgba(255, 94, 126, 0.1);
    color: var(--brand-accent);
}

.avatar-anon[b-ls742xf6hj] {
    background: rgba(255, 255, 255, 0.15);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.3);
    backdrop-filter: blur(8px);
    box-shadow: none;
}

/* ── Compact mode ─────────────────────────────────────────────────────────
   Full-screen pages (e.g. the tournament live page) force the mobile/collapsed
   layout at every width: hamburger + avatar only, the menu drops into a panel
   below the row, and the desktop language switch is hidden. Mirrors the
   max-width:760px block below so the two stay in lock-step. */
.top-nav.compact[b-ls742xf6hj] {
    gap: 12px;
    padding: 10px 18px;
    flex-wrap: wrap;
}

.top-nav.compact .hamburger[b-ls742xf6hj] {
    display: inline-flex;
    order: 3;
}

.top-nav.compact .menu[b-ls742xf6hj] {
    display: none;
    order: 4;
    flex: 0 0 100%;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 4px;
    padding: 8px;
    margin: 4px -6px 0;
    background: rgba(0, 0, 0, 0.18);
    border-radius: 14px;
    backdrop-filter: blur(8px);
    position: relative;
}

.top-nav.compact .menu.open[b-ls742xf6hj] {
    display: flex;
}

.top-nav.compact .menu[b-ls742xf6hj]  .menu-link {
    display: block;
    text-align: left;
    padding: 7px 16px;
    font-size: 15px;
    line-height: 1.4;
}

.top-nav.compact .menu-group[b-ls742xf6hj] {
    display: flex;
    flex-direction: column;
}

.top-nav.compact .menu-group-toggle[b-ls742xf6hj] {
    justify-content: space-between;
}

.top-nav.compact .menu .menu-dropdown[b-ls742xf6hj] {
    position: static;
    transform: none;
    margin-top: 4px;
    box-shadow: none;
    background: #ffffff;
    border: 1px solid #e6eaee;
}

.top-nav.compact .actions[b-ls742xf6hj] {
    margin-left: auto;
    order: 2;
}

.top-nav.compact .lang-group-desktop[b-ls742xf6hj] {
    display: none;
}

.top-nav.compact .lang-group-mobile[b-ls742xf6hj] {
    display: inline-flex;
    position: absolute;
    top: 8px;
    right: 8px;
    background: rgba(255, 255, 255, 0.08);
}

/* ── Compact "paper" colour scheme ────────────────────────────────────────
   The compact bar is a white "paper" surface (see .nav-bar.compact in
   MainLayout.razor.css), so the contents flip from white-on-venue to
   dark-on-white with a coral-tinted brand mark. */
.top-nav.compact[b-ls742xf6hj] {
    color: #0f1620;
}

/* Brand mark tinted coral (the app's --brand-accent). */
.top-nav.compact .brand-icon[b-ls742xf6hj] {
    --brand-icon-color: var(--brand-accent);
}

.top-nav.compact .nav-title[b-ls742xf6hj] {
    color: #0f1620;
}

/* Neutral status pill (e.g. the schedule page's "Schedule") → light grey chip
   with dark text. The .live pill keeps its red fill (legible on white). */
.top-nav.compact .nav-badge[b-ls742xf6hj] {
    background: #eef2f5;
    border-color: #e0e6ea;
    color: #475569;
}

/* The live pill keeps its red fill on the white bar (the neutral rule above is more
   specific than the base .nav-badge.live, so restate it here to win). */
.top-nav.compact .nav-badge.live[b-ls742xf6hj] {
    background: rgba(220, 38, 38, 0.95);
    border-color: rgba(248, 113, 113, 1);
    color: #fff;
}

/* The "Me today" ticket keeps its violet on the white bar — that contrast is the whole point of the colour.
   Only the ring and the shadow change: a white-ish border vanishes against paper, and the lifted glow has to
   soften now that there is no gradient underneath it. */
.top-nav.compact .nav-myday[b-ls742xf6hj] {
    border-color: rgba(79, 70, 229, 0.32);
    box-shadow: 0 3px 12px rgba(79, 70, 229, 0.32), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

/* User avatar stays greyscale in the compact header — it ignores the per-user
   hue so it reads as neutral chrome rather than another accent colour. */
.top-nav.compact .avatar[b-ls742xf6hj] {
    background: #eceff2;
    color: #5b6b78;
    box-shadow: 0 2px 8px rgba(15, 22, 32, 0.10), inset 0 0 0 1px rgba(15, 22, 32, 0.06);
}

.top-nav.compact .avatar-hue[b-ls742xf6hj] {
    color: #5b6b78;
}

.top-nav.compact .avatar-anon[b-ls742xf6hj] {
    background: #eceff2;
    color: #5b6b78;
    border-color: #dfe4e8;
    box-shadow: none;
}

.top-nav.compact .hamburger[b-ls742xf6hj] {
    background: #fff;
    border-color: #d7dee4;
}

.top-nav.compact .hamburger span[b-ls742xf6hj] {
    background: #334155;
}

/* Opened nav panel is a very light greyscale surface (was near-black, which read
   as too punchy over the white paper bar). Links flip to dark text and use the
   coral accent on hover. */
.top-nav.compact .menu[b-ls742xf6hj] {
    background: #f4f6f8;
    border: 1px solid #e2e8f0;
}

.top-nav.compact .menu[b-ls742xf6hj]  .menu-link {
    color: #334155;
}

.top-nav.compact .menu[b-ls742xf6hj]  .menu-link:hover {
    background: rgba(255, 94, 126, 0.12);
    color: var(--brand-accent);
}

.top-nav.compact .menu[b-ls742xf6hj]  .menu-link.active {
    background: var(--brand-accent);
    color: #fff;
    box-shadow: none;
}

@media (max-width: 760px) {
    .top-nav[b-ls742xf6hj] {
        gap: 12px;
        padding: 16px 18px;
        flex-wrap: wrap;
    }

    .hamburger[b-ls742xf6hj] {
        display: inline-flex;
        order: 3;
    }

    /* Collapsed by default; .open expands into a full-width panel that drops
       below the nav row (wrapping order: 4 puts it on its own line). */
    .menu[b-ls742xf6hj] {
        display: none;
        order: 4;
        flex: 0 0 100%;
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: 4px;
        padding: 8px;
        margin: 4px -6px 0;
        background: rgba(0, 0, 0, 0.18);
        border-radius: 14px;
        backdrop-filter: blur(8px);
    }

    .menu.open[b-ls742xf6hj] {
        display: flex;
    }

    .menu[b-ls742xf6hj]  .menu-link {
        display: block;
        text-align: left;
        padding: 7px 16px;
        font-size: 15px;
        line-height: 1.4;
    }

    .menu-group[b-ls742xf6hj] {
        display: flex;
        flex-direction: column;
    }

    .menu-group-toggle[b-ls742xf6hj] {
        justify-content: space-between;
    }

    /* On mobile the Settings submenu expands inline rather than floating. */
    .menu .menu-dropdown[b-ls742xf6hj] {
        position: static;
        transform: none;
        margin-top: 4px;
        box-shadow: none;
        background: rgba(255, 255, 255, 0.92);
    }

    /* .menu carried flex:1 to push .actions to the right; once it's hidden
       the actions need their own auto margin to stay right-aligned. */
    .actions[b-ls742xf6hj] {
        margin-left: auto;
        order: 2;
    }

    .lang-group-desktop[b-ls742xf6hj] {
        display: none;
    }

    .menu[b-ls742xf6hj] {
        position: relative;
    }

    .lang-group-mobile[b-ls742xf6hj] {
        display: inline-flex;
        position: absolute;
        top: 8px;
        right: 8px;
        background: rgba(255, 255, 255, 0.08);
    }

    /* Phone widths: the pill gives up the court code and some padding, keeping the time — the one token that
       is worth the space — so it takes as little as possible from the tournament title beside it. */
    .nav-myday[b-ls742xf6hj] {
        margin-left: 6px;
    }

    .nav-myday-label[b-ls742xf6hj] {
        padding: 5px 10px;
        font-size: 11px;
    }

    .nav-myday-data[b-ls742xf6hj] {
        padding: 5px 10px;
        font-size: 11.5px;
    }

    .nav-myday-court[b-ls742xf6hj] {
        display: none;
    }
}
/* /Pages/AdminDashboardPage.razor.rz.scp.css */
/* Measure and gutters come from the shared .page-column (app.css); only the tail spacing is this page's own. */
.admin-dashboard[b-c30g56mo58] {
    padding-bottom: 60px;
}

@media (max-width: 760px) {
    .admin-dashboard[b-c30g56mo58] {
        padding-bottom: 48px;
    }
}

/* Air between the always-on KPI strip and the tab strip that scrolls its own body beneath it. */
.admin-dashboard[b-c30g56mo58]  .tab-control {
    margin-top: 20px;
}

.dashboard-asof[b-c30g56mo58] {
    margin: 22px 0 0;
    font-size: 12px;
    font-weight: 600;
    color: #898781;
}
/* /Pages/LiveMatchesSimulationPage.razor.rz.scp.css */
.live-sim-panel[b-arkf09nfag] {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    width: 100%;
}

.live-sim-intro[b-arkf09nfag] {
    color: var(--text-muted, #6b7280);
    margin: 0;
}

.live-sim-row[b-arkf09nfag] {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.live-sim-datetime[b-arkf09nfag] {
    max-width: 16rem;
}

.live-sim-field-label[b-arkf09nfag] {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
}

.live-sim-slider.is-disabled[b-arkf09nfag] {
    opacity: 0.5;
}

.live-sim-slider-track[b-arkf09nfag] {
    position: relative;
    padding-bottom: 2.5rem;
    /* The 00/24 hour labels sit at 0%/100% and are centred on the tick, so half of each spills past the
       track edges. Clip the horizontal overflow (not the vertical, which the ticks/labels rail needs) so a
       narrow viewport doesn't gain a page-level horizontal scrollbar. */
    overflow-x: clip;
}

.live-sim-slider-track input[type="range"][b-arkf09nfag] {
    width: 100%;
}

/* Tick rail: hour ticks tall, quarter-hour ticks short; per-minute granularity is the slider step (no tick). */
.live-sim-ticks[b-arkf09nfag] {
    position: relative;
    height: 0.75rem;
    margin-top: 0.25rem;
}

.live-sim-ticks .tick[b-arkf09nfag] {
    position: absolute;
    top: 0;
    width: 1px;
    background: var(--border-strong, #9ca3af);
    transform: translateX(-0.5px);
}

.live-sim-ticks .tick-hour[b-arkf09nfag] {
    height: 0.75rem;
    background: var(--text, #374151);
}

.live-sim-ticks .tick-quarter[b-arkf09nfag] {
    height: 0.4rem;
}

/* Hour labels aligned under the tall hour ticks. */
.live-sim-hour-labels[b-arkf09nfag] {
    position: relative;
    height: 1rem;
    margin-top: 0.25rem;
}

.live-sim-hour-labels .live-sim-hour-label[b-arkf09nfag] {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    font-size: 0.6rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted, #6b7280);
}

.live-sim-steppers .live-sim-step-input[b-arkf09nfag] {
    width: 8rem;
}
/* /Pages/MyProfilePage.razor.rz.scp.css */
.profile-section[b-tifzzxc1qu] {
    max-width: 520px;
}

.profile-identity[b-tifzzxc1qu] {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 18px;
    /* Inherited by the PlayerAvatar's circle (custom properties cross scoped-CSS boundaries). */
    --avatar-size: 56px;
}

.profile-name[b-tifzzxc1qu] {
    font-size: 18px;
    font-weight: 800;
    color: #0f2a36;
}

.profile-hint[b-tifzzxc1qu] {
    margin: 0 0 6px;
    font-size: 13px;
    color: #5b7280;
}
/* /Pages/PlayerProfilePage.razor.rz.scp.css */
/* Player profile. The hero (identity + rating gauge) renders into the shared app hero gradient via <PageHeader>,
   so it inherits the gradient + white text from .page-header; only the inner layout is styled here. Silver isn't a
   global brand token, so its three shades are inlined; gold/bronze reuse the :root vars from app.css. */

/* ---- HERO (inside the app hero band) ---- */
.pp-hero-inner[b-wvvyevwrwd] {
    display: flex;
    gap: 24px;
    align-items: center;
    flex-wrap: wrap;
}

.pp-id[b-wvvyevwrwd] {
    min-width: 0;
    flex: 1 1 200px;
}

.pp-name[b-wvvyevwrwd] {
    margin: 4px 0 0;
}

.pp-gauge[b-wvvyevwrwd] {
    flex: none;
    text-align: center;
}

.pp-ring[b-wvvyevwrwd] {
    position: relative;
    width: 120px;
    height: 120px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    /* Player-colour disc (the avatar colour, medium-dark) so the white number/ring read strongly on top of it. */
    background: var(--avatar-bg, var(--brand-primary, #0ea5b7));
    box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.25), 0 10px 24px rgba(0, 0, 0, 0.25);
}

/* SVG donut fills the ring: a dim track, a bright white progress arc (driven by --v), and a thin outer halo.
   White reads clearly on the warm hero gradient where the old magenta conic ring washed out. */
.pp-ring-svg[b-wvvyevwrwd] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.pp-ring-track[b-wvvyevwrwd] {
    fill: none;
    stroke: rgba(255, 255, 255, 0.24);
    stroke-width: 12;
}

/* pathLength="100" normalises the circumference so the dash length equals the percent; rotate -90° to start at 12 o'clock. */
.pp-ring-arc[b-wvvyevwrwd] {
    fill: none;
    stroke: #fff;
    stroke-width: 12;
    stroke-linecap: round;
    stroke-dasharray: var(--v) 100;
    transform: rotate(-90deg);
    transform-origin: 66px 66px;
}

.pp-ring-halo[b-wvvyevwrwd] {
    fill: none;
    stroke: rgba(255, 255, 255, 0.45);
    stroke-width: 1.5;
}

/* Transparent text container stacked above the SVG; the dark backing lives on .pp-ring itself. */
.pp-ring-core[b-wvvyevwrwd] {
    position: relative;
    z-index: 1;
    width: 94px;
    height: 94px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.pp-ring-num[b-wvvyevwrwd] {
    font-size: 30px;
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.02em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45), 0 2px 10px rgba(0, 0, 0, 0.35);
}

.pp-ring-of[b-wvvyevwrwd] {
    font-size: 11px;
    opacity: 0.85;
    font-weight: 700;
    margin-top: 3px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

.pp-ring-rel[b-wvvyevwrwd] {
    font-size: 11px;
    font-weight: 800;
    margin-top: 4px;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* ---- ADMIN PANEL (admin-only "log in as this player") ---- */
.pp-admin[b-wvvyevwrwd] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 0;
}

/* ---- CONTENT COLUMN ----
   The dashboard-style reading column (.page-column, app.css) holds every block on the page — figures, chart and
   results grid alike — so they all share one measure, and one rule gives them one rhythm. */
.pp-column > * + *[b-wvvyevwrwd] {
    margin-top: 16px;
}

/* ---- RATING TRAJECTORY ----
   The chart has a panel to itself here rather than one row of small multiples, so it gets a taller plot than
   the shared 56px default. */
.pp-chart[b-wvvyevwrwd] {
    --area-line-chart-height: 150px;
}

.pp-traj-cap[b-wvvyevwrwd] {
    display: flex;
    justify-content: space-between;
    font-size: 12px;
    font-weight: 700;
    color: #898781;
    margin-top: 10px;
}

/* ---- ROOKIE EMPTY STATE (player has never played a match) ----
   A "career under construction" card: hazard tape top and bottom, a road sign, and copy that makes clear
   the profile works and simply has no results yet. It carries the dashboard panel's chrome but none of its
   padding — the hazard tape has to run edge to edge. */
.pp-rookie[b-wvvyevwrwd] {
    background: #fff;
    border: 1px solid rgba(11, 11, 11, 0.1);
    border-radius: 14px;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.045);
    overflow: hidden;
    text-align: center;
}

.pp-rookie-tape[b-wvvyevwrwd] {
    height: 14px;
    background: repeating-linear-gradient(135deg, #ffcf5c 0 14px, #1f2937 14px 28px);
    opacity: 0.9;
}

.pp-rookie-body-inner[b-wvvyevwrwd] {
    padding: 42px 24px 44px;
}

.pp-rookie-signrow[b-wvvyevwrwd] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.pp-rookie-cone[b-wvvyevwrwd] {
    font-size: 40px;
    line-height: 1;
}

.pp-rookie-sign[b-wvvyevwrwd] {
    background: #ffcf5c;
    color: #1f2937;
    border: 3px solid #1f2937;
    border-radius: 10px;
    padding: 14px 22px;
    font-weight: 800;
    font-size: 15px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    transform: rotate(-2deg);
    box-shadow: 0 8px 18px rgba(15, 22, 32, 0.12);
}

.pp-rookie-title[b-wvvyevwrwd] {
    margin: 24px 0 0;
}

.pp-rookie-text[b-wvvyevwrwd] {
    margin: 10px auto 0;
    max-width: 50ch;
    font-size: 15.5px;
    line-height: 1.6;
    color: #64748b;
}

.pp-rookie-cta[b-wvvyevwrwd] {
    margin-top: 22px;
}

@media (max-width: 480px) {
    .pp-rookie-sign[b-wvvyevwrwd] {
        font-size: 13px;
        padding: 11px 14px;
    }

    .pp-rookie-cone[b-wvvyevwrwd] {
        font-size: 30px;
    }
}

/* ---- TOURNAMENTS (no card wrapper — bare heading + grid) ----
   The result column holds only a medal or a placement number; its width comes from the grid track declared
   further down, not from the table-layout 'width: 1%' trick this used before the grid took over.
   The wide table scrolls horizontally within the shared .table-scroll wrapper (app.css).
   ::deep pierces the QuickGrid-rendered th/td cells (they carry the column Class but not this component's scope). */
.table-scroll[b-wvvyevwrwd]  .pp-col-result {
    white-space: nowrap;
    text-align: center;
}

.pp-tlink[b-wvvyevwrwd] {
    font-weight: 800;
    color: var(--brand-primary-dark);
    text-decoration: none;
}

.pp-tlink:hover[b-wvvyevwrwd] {
    text-decoration: underline;
}

.pp-cat[b-wvvyevwrwd] {
    font-size: 13px;
    font-weight: 700;
    color: var(--brand-primary-dark);
    background: rgba(14, 165, 183, 0.1);
    border: 1px solid rgba(14, 165, 183, 0.2);
    padding: 3px 9px;
    border-radius: 999px;
    white-space: nowrap;
}

/* Off-podium placements are a bare number; the top three show a medal instead. Both sit on the same 28px line
   so the column's rows stay level whichever of the two a finish renders. */
.pp-finish[b-wvvyevwrwd] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    font-weight: 800;
    font-size: 13px;
    color: #475569;
}

.pp-medal[b-wvvyevwrwd] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    font-size: 20px;
    line-height: 1;
}

.pp-delta[b-wvvyevwrwd] {
    font-weight: 800;
    font-size: 13px;
    white-space: nowrap;
}

.pp-delta-up[b-wvvyevwrwd] {
    color: #16a34a;
}

.pp-delta-down[b-wvvyevwrwd] {
    color: #dc2626;
}

.pp-delta-flat[b-wvvyevwrwd] {
    color: #64748b;
}

/* ---- EXPANDABLE RESULT ROWS ----
   The grid is laid out by app.css's .data-table-expandable (CSS grid + display:contents rows), which is what
   lets the detail cell span the full row; the chevron control lives in QuickGridRowExpander. Only the column
   tracks are page business, since only this page knows its columns. Order: expander · result · tournament ·
   category · rating Δ · date. The min-width keeps the shared .table-scroll wrapper scrolling horizontally on
   a phone instead of crushing the tournament name. */
.table-scroll[b-wvvyevwrwd]  .pp-results {
    grid-template-columns: min-content min-content minmax(180px, 1fr) min-content min-content min-content;
    min-width: 680px;
}

/* Grid items stretch, so cell text would sit at the top of a row whose result cell is a 28px medal. Centre it
   back; the two rules after this restore the alignment the flex container takes over from text-align.
   ':not(.col-detail)' is load-bearing — this selector outranks app.css's collapse rule, so without it the
   closed detail cell would be laid out as a seventh item and knock every column out of its track. */
.table-scroll[b-wvvyevwrwd]  .pp-results > tbody > tr > td:not(.col-detail) {
    display: flex;
    align-items: center;
}

.table-scroll[b-wvvyevwrwd]  .pp-results > tbody > tr > td.col-num {
    justify-content: flex-end;
}

.table-scroll[b-wvvyevwrwd]  .pp-results > tbody > tr > td.pp-col-result {
    justify-content: center;
}

/* ---- MATCH BREAKDOWN (inside an expanded row) ----
   Three slices per match: the game, the odds it was played at, and what the rating did about it. The panel
   shares the row's white surface (see .data-table-expandable in app.css) — no tint, no rule between them. */
.pp-mx-title[b-wvvyevwrwd] {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #5b7280;
}

.pp-mx-empty[b-wvvyevwrwd] {
    margin: 0;
    font-size: 13px;
    color: #64748b;
}

/* Minimums add up to less than the grid's own 680px floor, so the panel never widens the table beyond what
   the summary row already needs — the whole thing scrolls as one inside .table-scroll. */
.pp-mx-row[b-wvvyevwrwd] {
    display: grid;
    grid-template-columns: minmax(240px, 1.1fr) 190px minmax(210px, 1.15fr);
    align-items: center;
    padding: 7px 0;
    border-top: 1px solid #eef0f3;
}

.pp-mx-row:first-of-type[b-wvvyevwrwd] {
    border-top: none;
}

.pp-mx-cell[b-wvvyevwrwd] {
    padding: 0 16px;
    min-width: 0;
}

.pp-mx-cell + .pp-mx-cell[b-wvvyevwrwd] {
    border-left: 1px solid #e7edf1;
}

.pp-mx-cell:first-child[b-wvvyevwrwd] {
    padding-left: 0;
}

.pp-mx-cell:last-child[b-wvvyevwrwd] {
    padding-right: 0;
}

/* ---- slice 1: the game ----
   Same anatomy as the results card on the player's day page (a row per team with per-set points and the sets
   taken), minus its card chrome and its own border. The stage caption is turned 90° into the gutter so it
   costs the row no height, and the outcome-coloured edge it carries replaces the W/L pill that used to sit
   on a header row above the score. minmax(0, 1fr) keeps a long set run from pushing past the slice. */
.pp-mx-box[b-wvvyevwrwd] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 9px;
}

.pp-mx-rail[b-wvvyevwrwd] {
    writing-mode: vertical-rl;
    padding: 1px 4px 1px 6px;
    border-left: 3px solid #16a34a;
    border-radius: 2px;
    font-size: 9.5px;
    letter-spacing: 0.02em;
    color: #5b7280;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: center;
}

.pp-mx-lost > .pp-mx-rail[b-wvvyevwrwd] {
    border-left-color: #dc2626;
}

.pp-mx-drew > .pp-mx-rail[b-wvvyevwrwd] {
    border-left-color: #64748b;
}

.pp-mx-side[b-wvvyevwrwd] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 0;
}

.pp-mx-side + .pp-mx-side[b-wvvyevwrwd] {
    border-top: 1px dashed rgba(15, 42, 54, 0.1);
}

/* Team-mates side by side rather than stacked — one name line per team instead of two. */
.pp-mx-players[b-wvvyevwrwd] {
    display: flex;
    flex-direction: row;
    gap: 12px;
    flex: 0 1 236px;
    min-width: 0;
    margin-right: auto;
}

    .pp-mx-players > *[b-wvvyevwrwd] {
        flex: 1 1 0;
        min-width: 0;
    }

.pp-mx-sets[b-wvvyevwrwd] {
    display: flex;
    gap: 6px;
}

.pp-mx-set[b-wvvyevwrwd] {
    min-width: 18px;
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    color: #5b7280;
    font-variant-numeric: tabular-nums;
}

.pp-mx-total[b-wvvyevwrwd] {
    min-width: 22px;
    text-align: center;
    font-size: 14px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    background: #eef1f3;
    border-radius: 5px;
}

/* The losing side fades, matching the live board's greyscale cue. Set on the row so the player chips
   inside inherit it. */
.pp-mx-side.is-lose[b-wvvyevwrwd] {
    opacity: 0.58;
}

    .pp-mx-side.is-lose .pp-mx-total[b-wvvyevwrwd] {
        background: #f3f5f6;
    }

/* ---- slice 2: the odds the match was played at ---- */
.pp-mx-stand[b-wvvyevwrwd] {
    font-size: 12px;
    font-weight: 800;
    margin-bottom: 6px;
}

    /* The longest standing plus its chance ("Slight favourite · 65% win") outgrows this column, so it has to
       wrap — nowrap here forces the break before the chance rather than inside it, which otherwise stranded
       "win" on a line of its own. */
    .pp-mx-stand span[b-wvvyevwrwd] {
        font-weight: 400;
        color: #8095a4;
        white-space: nowrap;
    }

/* Underdog (amber) on the left, favourite (blue) on the right, with the pin at the pre-match win chance.
   Deliberately NOT red/green: those two are already spoken for in this panel — the movement pill and the
   losing side's fade — where they mean gain and loss. Reusing them here would imply a favourite's odds are
   "good" and an underdog's are "bad", which is the wrong axis: the odds describe the match-up, not the
   result. Amber/blue is also the safest divergent pair for red-green colour blindness, the most common form,
   and the two ends differ in warmth as well as hue so the scale survives being read in greyscale. */
.pp-mx-meter[b-wvvyevwrwd] {
    position: relative;
    height: 7px;
    border-radius: 999px;
    background: linear-gradient(90deg, #f0cf9a, #e6e8ea 45%, #e6e8ea 55%, #9dc3e6);
}

.pp-mx-pin[b-wvvyevwrwd] {
    position: absolute;
    left: var(--pp-odds, 50%);
    top: -4px;
    width: 4px;
    height: 15px;
    border-radius: 2px;
    background: #0f2a36;
    transform: translateX(-2px);
    box-shadow: 0 0 0 2px #fff;
}

/* Spans the meter above it: your rating at the left end, the opponents' at the right, "vs" holding the
   middle. Reading the pin and the pair together says who was ahead and by how much. */
.pp-mx-vs[b-wvvyevwrwd] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    margin-top: 5px;
    font-size: 11px;
    color: #8095a4;
    font-variant-numeric: tabular-nums;
}

.pp-mx-versus[b-wvvyevwrwd] {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    opacity: 0.75;
}

/* ---- slice 3: the movement and why ---- */
.pp-mx-amount[b-wvvyevwrwd] {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* The movement is the answer this whole panel exists to give, so it gets a pill rather than being one more
   coloured number among the ratings around it. Scoped to the breakdown: the results grid's own Δ column
   stays plain text, where a pill per row would be noise. */
.pp-mx-amount .pp-delta[b-wvvyevwrwd] {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 12.5px;
    line-height: 1.5;
}

.pp-mx-amount .pp-delta-up[b-wvvyevwrwd] {
    background: rgba(22, 163, 74, 0.1);
}

.pp-mx-amount .pp-delta-down[b-wvvyevwrwd] {
    background: rgba(220, 38, 38, 0.1);
}

.pp-mx-amount .pp-delta-flat[b-wvvyevwrwd] {
    background: rgba(100, 116, 139, 0.12);
}

.pp-mx-move[b-wvvyevwrwd] {
    font-size: 11px;
    color: #8095a4;
    font-variant-numeric: tabular-nums;
}

.pp-mx-why[b-wvvyevwrwd] {
    margin: 4px 0 0;
    font-size: 12.5px;
    line-height: 1.45;
    color: #475569;
}

/* ---- RESPONSIVE ---- */
@media (max-width: 640px) {
    .pp-hero-inner[b-wvvyevwrwd] {
        gap: 14px 16px;
    }

    .pp-ring[b-wvvyevwrwd] {
        width: 92px;
        height: 92px;
    }

    .pp-ring-core[b-wvvyevwrwd] {
        width: 72px;
        height: 72px;
    }

    .pp-ring-num[b-wvvyevwrwd] {
        font-size: 24px;
    }

    .pp-chart[b-wvvyevwrwd] {
        --area-line-chart-height: 120px;
    }
}
/* /Pages/PlayersListPage.razor.rz.scp.css */
/* The leading column merges the avatar and the name into one cell, hard-capped at 300px.
   table-layout:fixed makes that fixed column width authoritative, so a long name truncates
   (ellipsis on .player-label-name) instead of stretching the column. */
.players-grid[b-t9qo48np07]  .data-table {
    table-layout: fixed;
}

.players-grid[b-t9qo48np07]  .col-player {
    width: 250px;
}

.player-cell[b-t9qo48np07] {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

/* The whole cell links to the player's profile; keep it looking like the plain cell (the name still hovers
   its own tooltip), only nudging the colour on hover to cue it's clickable. */
.player-cell-link[b-t9qo48np07] {
    text-decoration: none;
    color: inherit;
}

    .player-cell-link:hover[b-t9qo48np07]  .player-label-name {
        color: var(--brand-primary-dark);
    }

    /* Let the label take the slack next to the fixed-size avatar and shrink/truncate within the cap. */
    .player-cell[b-t9qo48np07]  .player-label {
        flex: 1;
        min-width: 0;
    }
/* /Pages/PlayerTodayPage.razor.rz.scp.css */
/* Phone-first, but the round tab hosts the full standings table, so the column is wide enough for it to
   breathe on a desktop. The gutter is deliberately small — the layout's own content padding already
   provides the page margin. */
.pt[b-1hhkw9sm2x] {
    width: 100%;
    max-width: 720px;
    margin: 0 auto;
    padding: 0 2px 40px;

    /* The width every player-names column on the page is measured against: the two cards at the top of the
       Next tab, the later-match rows below them, and the score rows on Results. Defined once here so a
       rating bar is the same length in all of them — a bar you can compare across rows is the whole point,
       and a Results column left free to stretch made its bars read as longer ratings. The Next-tab columns
       take it as a floor (they hug their names); the Results column takes it as a fixed basis, because it
       sits on the left of the row and would otherwise absorb all the slack ahead of the set scores. */
    --pt-names-w: 150px;
}

.pt-loading[b-1hhkw9sm2x] {
    display: grid;
    place-items: center;
    padding: 48px 0;
}

.pt-empty[b-1hhkw9sm2x],
.pt-hint[b-1hhkw9sm2x] {
    color: #5b7280;
    font-size: 13px;
    text-align: center;
    padding: 18px 4px;
}

.pt-hint[b-1hhkw9sm2x] {
    font-size: 11.5px;
    padding: 6px 4px 0;
}

/* Three short captions belong on one row: the shared strip asks 210px per column, which stacks them on a
   phone and pushes the day's first match below the fold. Reached with ::deep because the strip is authored
   inside TabControl, and scoped to this page so every other TabControl host keeps the wider default. */
.pt[b-1hhkw9sm2x]  .tab-strip {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
}

.pt[b-1hhkw9sm2x]  .tab-item {
    text-align: center;
    padding: 11px 6px;
}

/* The pool standings table can still outgrow a phone column — let it scroll here, not the whole page. */
.pt-panel-wide[b-1hhkw9sm2x] {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* ── Tournament line ────────────────────────────────────────────────────────
   Which tournament this day belongs to, between the hero and the tab strip: a ghost link out to that
   tournament's live board, led by the open-in-new-window glyph, with the button back to the picker — only
   when the player has more than one tournament running — pushed to the far right. The heading is the
   AppButton itself, so only its gutter and truncation are set here. Space-between rather than a margin on
   the switch: that button is rendered by AppButton, so a class handed to it never carries this page's scope
   attribute and a rule written against it would not match. */
.pt-tournament[b-1hhkw9sm2x] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0 4px 16px;
}

/* Flex rather than a plain block: it is what lets the link shrink — and only then — so a long name
   ellipsises instead of pushing the switch off the line. A percentage max-width on the link cannot do this,
   because the heading's own width is what that percentage would have to resolve against. */
.pt-tournament-name[b-1hhkw9sm2x] {
    display: flex;
    min-width: 0;
    margin: 0;
}

/* The button's own pill padding would indent the name past the cards below it; pulling it back by the same
   amount lands the glyph on the page's gutter while the hover tint keeps its breathing room. */
.pt-tournament-name[b-1hhkw9sm2x]  .app-btn {
    min-width: 0;
    margin-left: -12px;
    padding: 8px 12px;
}

.pt-tournament-text[b-1hhkw9sm2x] {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Tournament picker ──────────────────────────────────────────────────────
   One row per running tournament, shaped like the schedule rows below so the page reads as one thing. */
.pt-picker-hint[b-1hhkw9sm2x] {
    margin: 0 4px 12px;
    font-size: 13px;
    color: #5b7280;
}

.pt-picker[b-1hhkw9sm2x] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    background: #fff;
    border: 1px solid #e2e8ea;
    border-radius: 16px;
    box-shadow: 0 2px 8px rgba(10, 60, 70, 0.08);
    padding: 14px 16px;
    margin-bottom: 10px;
    color: inherit;
    text-decoration: none;
}

.pt-picker:hover[b-1hhkw9sm2x] {
    border-color: var(--brand-primary);
    box-shadow: 0 4px 14px rgba(10, 60, 70, 0.14);
}

/* The trailing chevron is the Icon component's own element, so it is reached across the boundary. */
.pt-picker[b-1hhkw9sm2x]  .bi {
    flex: none;
    color: #9aa0a4;
}

.pt-picker-main[b-1hhkw9sm2x] {
    min-width: 0;
}

.pt-picker-name[b-1hhkw9sm2x] {
    font-size: 15px;
    font-weight: 800;
    line-height: 1.25;
}

.pt-picker-meta[b-1hhkw9sm2x] {
    font-size: 12.5px;
    color: #5b7280;
    margin-top: 2px;
}

/* The panels' section headings ("Up next", "Which tournament?") — plain h3 typography; only the page's own
   gutter and vertical rhythm are set here. */
.pt-label[b-1hhkw9sm2x] {
    margin: 14px 4px 8px;
}

/* ── Match cards ────────────────────────────────────────────────────────────*/
.pt-card[b-1hhkw9sm2x] {
    position: relative;
    background: #fff;
    border: 1px solid #e2e8ea;
    border-radius: 16px;
    box-shadow: 0 2px 8px rgba(10, 60, 70, 0.08);
    padding: 14px 16px;
    margin-bottom: 10px;
    overflow: hidden;
}

.pt-card[b-1hhkw9sm2x]::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 5px;
    background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
}

.pt-card.is-live[b-1hhkw9sm2x]::before {
    background: linear-gradient(180deg, var(--brand-accent), var(--brand-accent-warm));
}

.pt-card.pt-result.is-win[b-1hhkw9sm2x]::before {
    background: #16a34a;
}

.pt-card.pt-result.is-loss[b-1hhkw9sm2x]::before {
    background: var(--brand-danger);
}

/* The results cards' header row: outcome badge beside the match meta. */
.pt-card-top[b-1hhkw9sm2x] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

/* The Next tab's two cards, laid out like the later-match rows below them (see .pt-sched): the slot time
   and its pill over the match meta on the left, the opponent's players on the right. */
.pt-card-row[b-1hhkw9sm2x] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
}

/* Shrinks so a long "Court 3 · Pool A · Quarterfinal 1" ellipsises rather than squeezing the names. */
.pt-card-left[b-1hhkw9sm2x] {
    min-width: 0;
}

/* The slot time and the card's pill — the live badge, or the countdown — read as one line. It wraps only
   on the narrowest phones, where a 21px time plus a pill can outgrow the left column. */
.pt-card-when[b-1hhkw9sm2x] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.pt-meta[b-1hhkw9sm2x] {
    font-size: 12.5px;
    color: #5b7280;
    flex: 1;
    min-width: 0;
}

.pt-time[b-1hhkw9sm2x] {
    font-size: 21px;
    font-weight: 800;
    letter-spacing: -0.3px;
}

.pt-count[b-1hhkw9sm2x] {
    font-size: 11.5px;
    font-weight: 800;
    color: #fff;
    background: var(--brand-accent);
    padding: 3px 10px;
    border-radius: 20px;
    white-space: nowrap;
}

/* Live pill in the card's top-right corner. */
.pt-live[b-1hhkw9sm2x] {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: #ffe9ee;
    color: #c2385a;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 20px;
    white-space: nowrap;
}

.pt-live-dot[b-1hhkw9sm2x] {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--brand-accent);
    animation: pt-pulse-b-1hhkw9sm2x 1.8s infinite;
}

@keyframes pt-pulse-b-1hhkw9sm2x {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.25); }
}

@media (prefers-reduced-motion: reduce) {
    .pt-live-dot[b-1hhkw9sm2x] {
        animation: none;
    }
}

/* Opponent block — the card's right-hand column, one player per row, sitting directly on the card (no
   tinted panel of its own). The gap carries the rating bar under each name, and the column's typography
   lives on the block so the player chips inherit it (see "Player labels" below). */
.pt-opp[b-1hhkw9sm2x] {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: var(--pt-names-w);
    text-align: right;
    font-size: 14px;
    font-weight: 700;
    line-height: 1.35;
}

/* The fallback caption for a slot that carries no players (a bare team name). */
.pt-opp-name[b-1hhkw9sm2x] {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pt-actions[b-1hhkw9sm2x] {
    display: flex;
    gap: 8px;
    margin-top: 11px;
}

.pt-btn[b-1hhkw9sm2x] {
    flex: 1;
    border: 1.5px solid var(--brand-primary);
    background: #fff;
    color: var(--brand-primary-dark);
    border-radius: 11px;
    padding: 12px;
    min-height: 44px;
    font-size: 14px;
    font-weight: 800;
    cursor: pointer;
}

.pt-btn:disabled[b-1hhkw9sm2x] {
    border-color: #d5dee1;
    color: #9aa0a4;
    cursor: not-allowed;
}

/* Confirming is the expected answer, so it carries the filled weight; disputing is the exception and stays
   an outline in the warning ink rather than shouting at the player from every finished match. */
.pt-btn-confirm[b-1hhkw9sm2x] {
    border-color: #16a34a;
    background: #16a34a;
    color: #fff;
}

.pt-btn-dispute[b-1hhkw9sm2x] {
    border-color: #d99a2b;
    color: #9a6a10;
}

/* The only action on the live card, and the one the day is waiting on — it carries the brand fill. */
.pt-btn-report[b-1hhkw9sm2x] {
    background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-dark));
    border-color: transparent;
    color: #fff;
}

/* ── Schedule ahead ─────────────────────────────────────────────────────────*/
.pt-gap[b-1hhkw9sm2x] {
    display: flex;
    justify-content: center;
    margin: 14px 0;
}

.pt-gap span[b-1hhkw9sm2x] {
    background: #e4ebed;
    color: #5b7280;
    font-size: 11.5px;
    font-weight: 700;
    padding: 6px 14px;
    border-radius: 20px;
}

.pt-sched[b-1hhkw9sm2x] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    background: #fff;
    border: 1px solid #e2e8ea;
    border-radius: 16px;
    box-shadow: 0 2px 8px rgba(10, 60, 70, 0.08);
    padding: 11px 14px;
    margin-bottom: 10px;
}

/* An undecided later-round slot: the live board's dashed outline. */
.pt-sched.is-future[b-1hhkw9sm2x] {
    border-style: dashed;
    border-color: #bcd3d8;
    box-shadow: none;
}

.pt-sched-time[b-1hhkw9sm2x] {
    font-size: 15px;
    font-weight: 800;
}

.pt-sched-court[b-1hhkw9sm2x] {
    font-size: 11.5px;
    color: #5b7280;
    margin-top: 1px;
}

/* Same shape as .pt-opp: a column of player chips that inherit the column's typography. */
.pt-sched-right[b-1hhkw9sm2x] {
    display: flex;
    flex-direction: column;
    gap: 6px;
    text-align: right;
    min-width: var(--pt-names-w);
    font-size: 13px;
    font-weight: 700;
    line-height: 1.35;
}

/* The live board's placeholder pill for a slot whose team isn't decided yet. Both hosts (.pt-opp and
   .pt-sched-right) are right-aligned flex columns of player labels, so the pill has to opt out of
   stretching and hug its caption at the column's trailing edge. */
.pt-future-pill[b-1hhkw9sm2x] {
    align-self: flex-end;
    display: inline-block;
    border-radius: 4px;
    padding: 4px 11px;
    color: #80969f;
    font-size: 13px;
    font-weight: 700;
    background: linear-gradient(90deg, #f2f6f7 25%, #ebecec 37%, #f2f6f7 63%);
    background-size: 400% 100%;
    animation: pt-future-sweep-b-1hhkw9sm2x 1.6s ease-in-out infinite;
}

@keyframes pt-future-sweep-b-1hhkw9sm2x {
    0% { background-position: 100% 0; }
    100% { background-position: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
    .pt-future-pill[b-1hhkw9sm2x] {
        animation: none;
    }
}

/* ── Results ────────────────────────────────────────────────────────────────
   The live board's match block: a row per team, a column per set, then the sets taken. */
.pt-wl[b-1hhkw9sm2x] {
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 800;
    color: #fff;
    flex: none;
}

.pt-wl.is-win[b-1hhkw9sm2x] {
    background: #16a34a;
}

.pt-wl.is-loss[b-1hhkw9sm2x] {
    background: var(--brand-danger);
}

.pt-score[b-1hhkw9sm2x] {
    overflow: hidden;
}

.pt-score-row[b-1hhkw9sm2x] {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
}

.pt-score-row + .pt-score-row[b-1hhkw9sm2x] {
    border-top: 1px dashed rgba(15, 42, 54, 0.10);
}

/* Pinned to the shared names width rather than left to grow: this column leads the row, so flexing it would
   hand it every spare pixel and stretch the rating bars past the length the Next tab's bars have — the same
   rating would read as two different bars across the two tabs. `margin-right: auto` gives the slack it no
   longer takes to the gap before the set scores, which keeps those pinned to the row's trailing edge. */
.pt-score-names[b-1hhkw9sm2x] {
    display: flex;
    flex-direction: column;
    gap: 5px;
    flex: 0 1 var(--pt-names-w);
    min-width: 0;
    margin-right: auto;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.25;
}

/* The fallback caption for a team row with no players behind it. */
.pt-score-name[b-1hhkw9sm2x] {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pt-score-sets[b-1hhkw9sm2x] {
    display: flex;
    gap: 6px;
}

.pt-set[b-1hhkw9sm2x] {
    min-width: 18px;
    text-align: center;
    font-size: 11px;
    font-weight: 700;
    color: #5b7280;
    font-variant-numeric: tabular-nums;
}

.pt-score-total[b-1hhkw9sm2x] {
    min-width: 26px;
    text-align: center;
    font-size: 16px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    background: #eef1f3;
    border-radius: 6px;
    padding: 2px 0;
}

/* Greyscale outcome cue, matching the live board: the winning row keeps full ink, the loser fades. Set on
   the names column rather than each name, so the player chips inside it inherit the cue too. */
.pt-score-row.is-win .pt-score-names[b-1hhkw9sm2x],
.pt-score-row.is-win .pt-score-total[b-1hhkw9sm2x] {
    color: #0f2a36;
}

.pt-score-row.is-win .pt-score-names[b-1hhkw9sm2x] {
    font-weight: 800;
}

.pt-score-row.is-lose .pt-score-names[b-1hhkw9sm2x],
.pt-score-row.is-lose .pt-score-total[b-1hhkw9sm2x] {
    color: #9aa0a4;
}

/* ── Result confirmation ────────────────────────────────────────────────────
   Sits under a finished match's score block: where the two teams stand on it, any dispute note, and the
   player's own two buttons. Separated by a rule rather than a panel — it belongs to the card above it. */
.pt-confirm[b-1hhkw9sm2x] {
    margin-top: 11px;
    padding-top: 10px;
}

.pt-confirm-state[b-1hhkw9sm2x] {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 12px;
    font-weight: 700;
}

.pt-confirm-state.is-disputed[b-1hhkw9sm2x] {
    color: #9a6a10;
}

.pt-confirm-state.is-pending[b-1hhkw9sm2x] {
    color: #5b7280;
}

/* The disputing player's own words — tinted and italic so they read as reported speech, not app copy. */
.pt-confirm-note[b-1hhkw9sm2x] {
    margin: 7px 0 0;
    padding: 7px 10px;
    background: #fdf6e7;
    border-radius: 8px;
    font-size: 12.5px;
    font-style: italic;
    line-height: 1.4;
    color: #6b5623;
}

.pt-confirm-prompt[b-1hhkw9sm2x] {
    margin: 9px 0 0;
    font-size: 12.5px;
    color: #5b7280;
}

/* ── Player labels ──────────────────────────────────────────────────────────
   Opponents, the schedule ahead and the score rows render each player as a PlayerLabel (name over a thin
   rating bar). Its root element belongs to that component, so it carries the component's scope attribute
   and this page's plain `.pt-*-name` rules can never match it — the typography therefore lives on the
   page-authored container above and the chip's inner name drops its component defaults to inherit it,
   including the win/lose ink. ::deep is what reaches across into the child component's markup. The
   `min-width: 0` and the nowrap/ellipsis that truncate a long name in the column are PlayerLabel's own —
   nothing to restate here. */
.pt-opp[b-1hhkw9sm2x]  .player-label .player-label-name,
.pt-sched-right[b-1hhkw9sm2x]  .player-label .player-label-name,
.pt-score-names[b-1hhkw9sm2x]  .player-label .player-label-name {
    font-size: inherit;
    line-height: inherit;
    font-weight: inherit;
    color: inherit;
}
/* /Pages/RegistrationsSimulationPage.razor.rz.scp.css */
/* Keeps the destructive-action warning pinned while the tournament list scrolls. */
.reg-sim-warning[b-1wjfj70162] {
    position: sticky;
    top: 0.5rem;
    z-index: 10;
    margin-bottom: 0.5rem;
}

.reg-sim-panel[b-1wjfj70162] {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    width: 100%;
}

.reg-sim-intro[b-1wjfj70162],
.reg-sim-empty[b-1wjfj70162] {
    color: var(--text-muted, #6b7280);
    margin: 0;
}

.reg-sim-section-title[b-1wjfj70162] {
    margin: 0;
}

.reg-sim-tournaments[b-1wjfj70162] {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* Accordion item: the header button expands the categories inside the same card. */
.reg-sim-tournament[b-1wjfj70162] {
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.5rem;
    background: var(--surface, #ffffff);
}

.reg-sim-tournament.selected[b-1wjfj70162] {
    border-color: var(--primary, #2563eb);
    outline: 2px solid var(--primary, #2563eb);
    outline-offset: -1px;
}

.reg-sim-tournament-head[b-1wjfj70162] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    padding: 0.6rem 0.9rem;
    border: none;
    border-radius: 0.5rem;
    background: transparent;
    cursor: pointer;
    text-align: left;
    font: inherit;
}

.reg-sim-tournament:hover:not(.selected)[b-1wjfj70162] {
    border-color: var(--border-strong, #9ca3af);
}

.reg-sim-tournament-head:disabled[b-1wjfj70162] {
    opacity: 0.6;
    cursor: default;
}

.reg-sim-tournament-name[b-1wjfj70162] {
    font-weight: 600;
}

.reg-sim-tournament-meta[b-1wjfj70162] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
}

.reg-sim-state[b-1wjfj70162] {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: var(--surface-muted, #f3f4f6);
    color: var(--text-muted, #6b7280);
}

.reg-sim-state-open[b-1wjfj70162] {
    background: var(--success-bg, #dcfce7);
    color: var(--success, #16a34a);
}

.reg-sim-state-started[b-1wjfj70162] {
    background: var(--danger-bg, #fee2e2);
    color: var(--danger, #dc2626);
}

.reg-sim-date[b-1wjfj70162] {
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}

.reg-sim-categories[b-1wjfj70162] {
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--border, #d1d5db);
    padding: 0.5rem 0.9rem 0.75rem;
}

.reg-sim-category[b-1wjfj70162] {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.5rem 0;
}

.reg-sim-category + .reg-sim-category[b-1wjfj70162] {
    border-top: 1px dashed var(--border, #e5e7eb);
}

.reg-sim-category-name[b-1wjfj70162] {
    font-weight: 600;
    font-size: 0.9rem;
}

.reg-sim-range-row[b-1wjfj70162] {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.reg-sim-range-row input[type="range"][b-1wjfj70162] {
    flex: 1;
    min-width: 0;
}

.reg-sim-count[b-1wjfj70162] {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    min-width: 4.5rem;
    text-align: right;
}
/* /Pages/ResultsListPage.razor.rz.scp.css */
/* Completed tournaments in a QuickGrid (see app.css for .data-table/.table-scroll). Only the cell contents
   are styled here; the table chrome is shared with the other list pages. */

.results-link[b-rziwo5qv8u] {
    font-weight: 800;
    color: var(--brand-primary-dark);
    text-decoration: none;
}

.results-link:hover[b-rziwo5qv8u] {
    text-decoration: underline;
}

/* A tournament whose placements haven't been computed yet still lists — the pill says why the link
   shows no standings. */
.results-pending[b-rziwo5qv8u] {
    margin-left: 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--brand-primary-dark);
    background: rgba(14, 165, 183, 0.1);
    border-radius: 999px;
    padding: 3px 9px;
    white-space: nowrap;
}

/* Every category of the tournament sits in this one cell, so it's the widest in the table: capped, with the
   groups wrapping onto as many lines as they need rather than stretching the row.
   ::deep pierces the QuickGrid-rendered th/td (they carry the column Class but not this component's scope). */
.table-scroll[b-rziwo5qv8u]  .col-cats {
    max-width: 520px;
}

.results-cats[b-rziwo5qv8u] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px 8px;
}

/* One group per (size, skill) the categories share: the label is printed once and the genders that ran it
   hang off it, which is what keeps a four-category tournament on a single line. */
.results-group[b-rziwo5qv8u] {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 22px;
    padding: 0 6px 0 8px;
    border: 1px solid rgba(14, 165, 183, 0.22);
    border-radius: 8px;
    background: rgba(14, 165, 183, 0.06);
}

.results-group-skill[b-rziwo5qv8u] {
    font-size: 12px;
    font-weight: 800;
    color: var(--brand-primary-dark);
    white-space: nowrap;
}

.results-group-size[b-rziwo5qv8u] {
    font-size: 10px;
    font-weight: 700;
    color: #5b7280;
    white-space: nowrap;
}

/* One badge per gender in the group — a single letter plus the teams that played, and the link to that
   category's standings. The colour is what makes a wrapped row of them scannable at a glance. */
.results-gender[b-rziwo5qv8u] {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 5px;
    border-radius: 5px;
    font-size: 11px;
    font-weight: 800;
    line-height: 14px;
    color: #fff;
    text-decoration: none;
    background: var(--brand-primary);
    transition: filter 0.12s;
}

.results-gender:hover[b-rziwo5qv8u] {
    filter: brightness(1.12);
}

.results-gender-female[b-rziwo5qv8u] {
    background: #b5559b;
}

.results-gender-mixed[b-rziwo5qv8u] {
    background: #6b7fd7;
}

.results-gender-code[b-rziwo5qv8u] {
    font-size: 10px;
    opacity: 0.8;
}

/* The venue keeps the colour it wears everywhere else, carried in as --rc-hue on the cell. */
.results-venue[b-rziwo5qv8u] {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

.results-venue-dot[b-rziwo5qv8u] {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: hsl(var(--rc-hue, 190), 60%, 45%);
}
/* /Pages/TournamentLivePage.razor.rz.scp.css */
/* The viewport-locked page shell (column-flex frame + the body/​.page/​main/​.content
   height-chain re-plumbing) lives in app.css on `.app-viewport-locked`, which this
   page's root carries. This file only styles the live board's own toolbar. */

/* Fixed working strip carrying, on one row: the organiser settings gear, the player search, and the
   per-category round strip. Mirrors the schedule page's tinted toolbar. Stays fixed in view while the
   timeline (.app-scroll-region) owns all scrolling. The row itself never wraps — the three groups stay in
   line and only the category strip (.tl-cats, which can shrink) gives up space when the screen is narrow. */
.tl-toolbar[b-f24rvtxcwn] {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 0.75rem;
    padding: 9px 12px;
    background: white;
    border-bottom: 1px solid var(--border-color, #e2e6ea);
}

/* The settings gear leads the row and keeps its natural (circular icon) size; the anchor also
   positions the dropdown panel (see .app-menu in app.css). */
.tl-settings[b-f24rvtxcwn] {
    flex: 0 0 auto;
}

/* While the menu is open the gear stays in its hover tint so the anchor reads as active. */
.tl-settings[b-f24rvtxcwn]  .tl-gear.is-active {
    background: rgba(10, 111, 125, 0.18);
}

/* The reorganise toggle now lives inside the timeline's sticky Court header cell (injected through
   CourtHeaderContent, so this page still owns its look). Compact 26px circle to fit the header row. */
.tl-reorg-wrap[b-f24rvtxcwn] {
    display: inline-flex;
}

.tl-reorg-wrap[b-f24rvtxcwn]  .tl-reorg {
    width: 26px;
    height: 26px;
    min-width: 26px;
    min-height: 26px;
    font-size: 13px;
}

/* Active (reorganising) state: tint the icon button coral so the on state reads at a glance. */
.tl-reorg-wrap[b-f24rvtxcwn]  .tl-reorg.is-active {
    background: var(--brand-accent, #ff5e7e);
    color: #fff;
}

.tl-reorg-wrap[b-f24rvtxcwn]  .tl-reorg.is-active:hover:not(:disabled) {
    background: var(--brand-accent, #ff5e7e);
    filter: brightness(0.95);
}

/* Compact search — about half its former width; the `.as-form-field` variant in app.css stretches the
   search group to width:100%, so this fixed-width wrapper owns the sizing. Keeps its size as the row narrows. */
.tl-search[b-f24rvtxcwn] {
    flex: 0 0 170px;
    min-width: 0;
}

/* Results slot straight after the search: the organiser's confirm button, the calculating notice, or the
   link to the published standings. Keeps its natural size like the gear + search. */
.tl-results-slot[b-f24rvtxcwn] {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
}

.tl-results-slot[b-f24rvtxcwn]  .tl-confirm-results,
.tl-results-slot[b-f24rvtxcwn]  .tl-view-results {
    white-space: nowrap;
}

/* "Calculating results…" notice shown between confirmation and the job publishing the standings. */
.tl-calculating[b-f24rvtxcwn] {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(10, 111, 125, 0.10);
    color: var(--brand-primary, #0a6f7d);
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
}

.tl-calculating-dot[b-f24rvtxcwn] {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    animation: tl-calculating-pulse-b-f24rvtxcwn 1.2s ease-in-out infinite;
}

@keyframes tl-calculating-pulse-b-f24rvtxcwn {
    0%, 100% { opacity: 0.35; transform: scale(0.8); }
    50% { opacity: 1; transform: scale(1); }
}

/* The state is fully conveyed by the label; stop the decorative pulse for reduced-motion users. */
@media (prefers-reduced-motion: reduce) {
    .tl-calculating-dot[b-f24rvtxcwn] {
        animation: none;
    }
}

/* The per-category round strip, pushed to the right edge. It is the only flexible group, so it absorbs the
   leftover width and is the first to collapse when the screen is narrow (min-width:0 lets the inner band
   shrink and wrap its cells onto further rows). */
.tl-cats[b-f24rvtxcwn] {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    justify-content: flex-end;
}

/* In the consolidated toolbar the band no longer paints its own surface (the toolbar owns the background
   and divider); its cells wrap toward the right edge and collapse first when space runs out. */
.tl-cats[b-f24rvtxcwn]  .cr-band {
    background: transparent;
    border-bottom: none;
    padding: 0;
    justify-content: flex-end;
}

/* The reorganise-mode court header (rotated court-name spine + group strips) lives in the timeline's own
   scoped CSS (.tl-grouped-header), shared with the schedule page. This page only drives the sticky column
   width by setting --ts-courtw inline on the scroll region while editing (see the .tl-editing wrapper). */

/* Phone layout: the single nowrap row would force the category strip to share width with the controls,
   eating half the screen. Instead the toolbar wraps onto two rows — the settings gear + search keep the
   first row to themselves (the search grows to claim the slack the fixed 170px no longer reserves), and
   the category-rounds strip drops to its own full-width row below where the chevrons can use the whole
   screen width. */
@media (max-width: 760px) {
    .tl-toolbar[b-f24rvtxcwn] {
        flex-wrap: wrap;
    }

    /* Search fills the rest of the first row beside the settings gear, instead of its fixed desktop width. */
    .tl-search[b-f24rvtxcwn] {
        flex: 1 1 auto;
    }

    /* Category strip takes a full-width second row; flow its cards from the left so the surplus gap (if any)
       sits on the right rather than indenting the cluster. */
    .tl-cats[b-f24rvtxcwn] {
        flex: 1 0 100%;
        justify-content: flex-start;
    }

    .tl-cats[b-f24rvtxcwn]  .cr-band {
        justify-content: flex-start;
    }
}
/* /Pages/TournamentOverviewPage.razor.rz.scp.css */
.td-hero-layout[b-783exm3pm9] {
    display: flex;
    align-items: flex-start;
    gap: 32px;
    flex-wrap: wrap;
}

.td-hero-main[b-783exm3pm9] {
    flex: 1 1 320px;
    min-width: 0;
}

.td-status-badge[b-783exm3pm9] {
    position: absolute;
    bottom: 14px;
    right: 28px;
    z-index: 3;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.35);
    white-space: nowrap;
}

.td-status-badge.td-status-draft[b-783exm3pm9] {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.25);
}

.td-status-badge.td-status-open[b-783exm3pm9] {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.85);
    color: #fff;
}

.td-status-badge.td-status-closed[b-783exm3pm9] {
    background: rgba(0, 0, 0, 0.35);
    border-color: rgba(255, 255, 255, 0.25);
}

.td-status-badge.td-status-started[b-783exm3pm9] {
    background: rgba(220, 38, 38, 0.95);
    border-color: rgba(248, 113, 113, 1);
}

.td-status-badge.td-status-link[b-783exm3pm9] {
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s, box-shadow 0.15s;
}

.td-status-badge.td-status-link:hover[b-783exm3pm9] {
    background: rgba(220, 38, 38, 1);
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(220, 38, 38, 0.4);
}

.td-status-chevron[b-783exm3pm9] {
    font-size: 11px;
    margin-left: -1px;
}

.td-status-dot[b-783exm3pm9] {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    animation: td-live-pulse-b-783exm3pm9 1.5s ease-out infinite;
}

@keyframes td-live-pulse-b-783exm3pm9 {
    0% {
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    }
    70% {
        box-shadow: 0 0 0 7px rgba(255, 255, 255, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
    }
}

/* Respect reduced-motion: hold the live status dot steady, no outgoing wave. */
@media (prefers-reduced-motion: reduce) {
    .td-status-dot[b-783exm3pm9] {
        animation: none;
    }
}

@media (max-width: 760px) {
    .td-status-badge[b-783exm3pm9] {
        right: 18px;
    }
}

.td-hero-map[b-783exm3pm9] {
    flex: 1 1 280px;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    /* Keep the map clear of the bottom-right status pill so it sits between
       the countdown and the pill rather than overlapping it. */
    padding-right: 120px;
}

@media (max-width: 760px) {
    .td-hero-map[b-783exm3pm9] {
        justify-content: center;
        padding-right: 0;
    }
}

.td-hero-row[b-783exm3pm9] {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 18px;
    margin-top: 18px;
}

.td-hero-date[b-783exm3pm9] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 88px;
    min-height: 88px;
    flex: 0 0 auto;
    padding: 10px;
    border-radius: 12px;
    background: #fff;
    color: #0d0d0d;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28);
    line-height: 1;
}

.td-hero-date-day[b-783exm3pm9] {
    font-size: 34px;
    font-weight: 900;
    letter-spacing: -0.02em;
}

.td-hero-date-month[b-783exm3pm9] {
    margin-top: 5px;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    opacity: 1;
}

.td-hero-date-year[b-783exm3pm9] {
    margin-top: 3px;
    font-size: 12px;
    font-weight: 600;
    opacity: 0.6;
}

.td-hero-date-time[b-783exm3pm9] {
    margin-top: 4px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
}

@media (max-width: 760px) {
    .td-hero-main[b-783exm3pm9] {
        text-align: center;
    }

    .td-hero-row[b-783exm3pm9] {
        justify-content: center;
    }
}

.td-register[b-783exm3pm9] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
}

.td-reg-status[b-783exm3pm9] {
    display: inline-flex;
    flex-direction: column;
    line-height: 1.2;
    padding: 4px 0;
    font-size: 14px;
    font-weight: 700;
    color: #15803d;
    margin-left: auto;
    text-align: right;
}

.td-reg-status small[b-783exm3pm9] {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #94a3b8;
}

.td-reg-status.closed[b-783exm3pm9] {
    color: #64748b;
}

/* Registered state — a success Banner with custom content, capped at a
   mobile screen width. The inner .banner belongs to the Banner component, so
   reach it via ::deep to lay its icon + custom content out as a single row. */
.td-myreg-wrap[b-783exm3pm9] {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 430px;
    /* Inherited by the PlayerAvatarList avatars rendered inside the banner. */
    --avatar-size: 26px;
    --avatar-ring: #f0fdf4;
}

.td-myreg-wrap[b-783exm3pm9]  .banner {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0;
}

.td-myreg-wrap[b-783exm3pm9]  .banner > i {
    margin-right: 0;
    font-size: 18px;
}

.td-myreg-text[b-783exm3pm9] {
    display: flex;
    flex-direction: column;
    line-height: 1.1;
    min-width: 0;
    flex: 1 1 auto;
}

.td-myreg-title[b-783exm3pm9] {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.85;
}

.td-myreg-team-name[b-783exm3pm9] {
    font-size: 14px;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.td-myreg-unregister[b-783exm3pm9] {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 1px solid #d8e1ea;
    background: #fff;
    color: #64748b;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 14px;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}

.td-myreg-unregister:hover[b-783exm3pm9] {
    background: #fef2f2;
    color: #dc2626;
    border-color: #fecaca;
}

.td-hero-meta[b-783exm3pm9] {
    font-weight: 600;
    opacity: 0.92;
}

.td-section[b-783exm3pm9] {
    margin: 28px 0;
}

.td-h2[b-783exm3pm9] {
    margin: 0 0 14px;
}

.td-about-body[b-783exm3pm9] {
    background: #fff;
    border-radius: 14px;
    padding: 18px 22px;
    margin: 0;
    color: #2c3e50;
    line-height: 1.55;
    white-space: pre-wrap;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
}


.td-format-hint[b-783exm3pm9] {
    margin: -6px 0 14px;
    color: #6b7a8d;
    font-size: 13px;
}

.td-rounds[b-783exm3pm9] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
    position: relative;
}

.td-rounds[b-783exm3pm9]::before {
    content: "";
    position: absolute;
    left: 21px;
    top: 8px;
    bottom: 8px;
    width: 2px;
    background: linear-gradient(180deg, var(--brand-primary, #0ea5b7), var(--brand-accent, #ff7e5f));
    border-radius: 2px;
    opacity: 0.35;
}

.td-round[b-783exm3pm9] {
    position: relative;
    display: grid;
    grid-template-columns: 44px 1fr;
    gap: 16px;
    align-items: start;
    background: #fff;
    border-radius: 14px;
    padding: 16px 18px;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
}

.td-round-num[b-783exm3pm9] {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    background: linear-gradient(135deg, var(--brand-primary, #0ea5b7), var(--brand-primary-deep, #0a6f7d));
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 900;
    font-size: 18px;
    letter-spacing: -0.02em;
    z-index: 1;
}

.td-round-main[b-783exm3pm9] {
    min-width: 0;
}

.td-round-eyebrow[b-783exm3pm9] {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #9aa8b5;
    margin-bottom: 3px;
}

.td-round-head[b-783exm3pm9] {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid #e7ebee;
}

.td-round-name[b-783exm3pm9] {
    font-size: 18px;
    font-weight: 800;
    color: var(--brand-primary-deep, #0a6f7d);
    letter-spacing: -0.01em;
}

.td-round-specs[b-783exm3pm9] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 12px 18px;
}

.td-round-specs .spec-k[b-783exm3pm9] {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #5b7280;
    margin-bottom: 2px;
}

.td-round-specs .spec-v[b-783exm3pm9] {
    font-size: 14px;
    font-weight: 700;
    color: #102a43;
}

.td-round-specs .spec-v small[b-783exm3pm9] {
    font-weight: 500;
    color: #5b7280;
}

.td-announcements[b-783exm3pm9] {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.td-ann[b-783exm3pm9] {
    background: #fff;
    border-radius: 14px;
    padding: 16px 18px;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
    border-left: 4px solid transparent;
}

.td-ann.pinned[b-783exm3pm9] {
    border-left-color: var(--brand-accent, #ff5e7e);
    background: linear-gradient(180deg, #fff8f2 0%, #fff 60%);
}

.td-ann-head[b-783exm3pm9] {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}

.td-ann-pin[b-783exm3pm9] {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #ff5e7e;
}

.td-ann-title[b-783exm3pm9] {
    font-size: 16px;
    font-weight: 700;
    margin: 0;
    color: #102a43;
}

.td-ann-date[b-783exm3pm9] {
    margin-left: auto;
    font-size: 12px;
    color: #6b7a8d;
}

.td-ann-body[b-783exm3pm9] {
    margin: 0;
    color: #2c3e50;
    line-height: 1.55;
    white-space: pre-wrap;
}

.td-ann-author[b-783exm3pm9] {
    margin-top: 8px;
    font-size: 12px;
    color: #6b7a8d;
    font-style: italic;
}

.td-org-list[b-783exm3pm9] {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.td-org[b-783exm3pm9] {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    background: #fff;
    border-radius: 999px;
    padding: 6px 14px 6px 6px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
    /* Inherited by the PlayerAvatar control. */
    --avatar-size: 32px;
}

.td-org.primary[b-783exm3pm9] {
    background: linear-gradient(135deg, #fff8f2, #fff);
    border: 1px solid #ffd9c2;
}

.td-org-name[b-783exm3pm9] {
    font-size: 14px;
    font-weight: 600;
    color: #102a43;
}

.td-org-badge[b-783exm3pm9] {
    color: #ff7e5f;
    font-size: 14px;
}

/* ── Admin section (top of overview) ───────────── */
.td-groups-visibility[b-783exm3pm9] {
    max-width: 420px;
}

.td-groups-visibility[b-783exm3pm9]  .form-radio-group {
    margin-bottom: 0;
}

/* ── First round groups ─────────────────────────── */
.td-org-control[b-783exm3pm9] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 180px;
}

.td-org-control-label[b-783exm3pm9] {
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #5b7280;
}

.td-org-select[b-783exm3pm9] {
    padding: 6px 10px;
    border: 1px solid #d8e1ea;
    border-radius: 8px;
    background: #fff;
    font-size: 14px;
}

.td-org-control-switch[b-783exm3pm9] {
    margin-left: auto;
    min-width: 0;
}

.td-org-btn[b-783exm3pm9] {
    align-self: flex-end;
}

.td-regen-status[b-783exm3pm9] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    font-size: 12px;
    color: #5b7280;
    margin: 0 0 14px;
}

.td-groups[b-783exm3pm9] {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.td-group[b-783exm3pm9] {
    background: #fff;
    border-radius: 14px;
    padding: 10px 14px;
    box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
}

.td-group-unseeded[b-783exm3pm9] {
    background: var(--bs-warning-bg-subtle);
    border: 1px dashed var(--bs-warning-border-subtle);
    box-shadow: none;
}

.td-group-header[b-783exm3pm9] {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
}

.td-group-badge[b-783exm3pm9] {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--brand-primary, #0ea5b7), var(--brand-primary-deep, #0a6f7d));
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 800;
    font-size: 14px;
}

.td-group-badge-muted[b-783exm3pm9] {
    background: #cdd6df;
    color: #5b7280;
}

.td-group-title[b-783exm3pm9] {
    margin: 0;
}

.td-group-count[b-783exm3pm9] {
    margin-left: auto;
    font-size: 12px;
    color: #6b7a8d;
    font-weight: 700;
}

.td-team-move-wrap[b-783exm3pm9] {
    margin-left: auto;
    position: relative;
    display: inline-flex;
}

.td-team-move-btn[b-783exm3pm9] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    color: #94a3b8;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.td-team-move-btn:hover[b-783exm3pm9],
.td-team-move-btn[aria-expanded="true"][b-783exm3pm9] {
    background: #f1f5f9;
    color: #0f2a36;
    border-color: #d8e1ea;
}

.td-team-move-btn i[b-783exm3pm9] {
    font-size: 16px;
}

.td-team-move-backdrop[b-783exm3pm9] {
    position: fixed;
    inset: 0;
    z-index: 40;
}

.td-team-move-pop[b-783exm3pm9] {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 50;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(10, 42, 54, 0.18), 0 0 0 1px rgba(10, 42, 54, 0.06);
    padding: 12px 14px;
    min-width: 200px;
}

/* The popover isn't a <form>, so FormInputRadioGroup renders without its surrounding
   card chrome — the popover itself is the box. Drop the control font-size to 60% so
   the em-based pill paddings/font/radii scale down proportionally for this dense UI. */
.td-team-move-pop[b-783exm3pm9]  .form-radio-control {
    font-size: 0.6rem;
}

/* Pills lay out as a fixed 2-column grid so every cell is the same width regardless
   of label length. */
.td-team-move-pop[b-783exm3pm9]  .form-radio-pills {
    display: grid;
    grid-auto-flow: row;
    grid-template-columns: repeat(2, 1fr);
}
/* /Pages/TournamentPoolPage.razor.rz.scp.css */
/* The public category-switcher chrome — locked frame, header bar, back link,
   category picker, pill groove and empty state — is shared with the bracket page
   and lives in app.css (`.app-viewport-locked` + the `.catbar*` family). This
   file only keeps the "advancement secured" legend, which is unique to the
   pool-standings page (the bracket has no such marker).

   The legend fills the `.catbar` grid's "legend" area — pinned to the right edge
   of the top row on every viewport (app.css defines the area placement). */
.gsp-legend[b-vknmch1kwn] {
    grid-area: legend;
    justify-self: end;
    display: inline-flex;
    align-items: center;
    gap: 14px;
    margin: 0;
    font-size: 11.5px;
    font-weight: 700;
    color: #5b7280;
    white-space: nowrap;
}

/* One key entry: its swatch/pill sample followed by the label. */
.gsp-lg-item[b-vknmch1kwn] {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.gsp-lg-q[b-vknmch1kwn] {
    width: 12px;
    height: 12px;
    border-radius: 3px;
    background: #9fe1cb;
}

/* Sample of the overall-placement pill from the tables (see PoolRoundFormat's .rpf-overall). */
.gsp-lg-rank[b-vknmch1kwn] {
    display: inline-grid;
    place-items: center;
    min-width: 16px;
    height: 15px;
    padding: 0 4px;
    border-radius: 999px;
    font-size: 9.5px;
    font-weight: 800;
    color: #fff;
    background: #0f2a36;
}

/* Sample of the plain group-rank cell from the tables (see PoolRoundFormat's .rpf-rank). */
.gsp-lg-grank[b-vknmch1kwn] {
    display: inline-grid;
    place-items: center;
    width: 15px;
    height: 15px;
    border-radius: 5px;
    font-size: 9.5px;
    font-weight: 800;
    color: #5b7280;
    background: #eef1f3;
}
/* /Pages/TournamentResultPage.razor.rz.scp.css */
/* Final standings. The top three get a floodlit arena — illustrated pairs on gold/silver/bronze blocks,
   sweeping light beams and corner confetti — while 4th and below is a plain ordered list underneath. */

/* ── the arena ──────────────────────────────────────────────────────────── */
.trs-arena[b-trrj0o93c9] {
    position: relative;
    max-width: 800px;
    margin: 1rem auto 0;
    border-radius: 18px;
    overflow: hidden;
    background: radial-gradient(120% 90% at 50% 8%, #1c4356 0%, #102a38 45%, #08161e 100%);
    box-shadow: 0 18px 50px rgba(8, 22, 30, 0.35);
    padding: 38px 0 0;
}

/* Spotlights sweeping the stage. `screen` keeps them additive over the dark backdrop. */
.trs-beams[b-trrj0o93c9] {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    mix-blend-mode: screen;
}

.trs-beam[b-trrj0o93c9] {
    position: absolute;
    top: -40%;
    left: 50%;
    width: 150px;
    height: 150%;
    filter: blur(14px);
    transform-origin: 50% 0;
    opacity: 0.7;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.05) 55%, transparent 80%);
}

.trs-beam-1[b-trrj0o93c9] {
    animation: trs-sweep-a-b-trrj0o93c9 7s ease-in-out infinite;
}

.trs-beam-2[b-trrj0o93c9] {
    background: linear-gradient(180deg, rgba(255, 222, 140, 0.35), rgba(255, 222, 140, 0.05) 55%, transparent 80%);
    animation: trs-sweep-b-b-trrj0o93c9 9s ease-in-out infinite;
}

.trs-beam-3[b-trrj0o93c9] {
    background: linear-gradient(180deg, rgba(126, 214, 232, 0.3), rgba(126, 214, 232, 0.04) 55%, transparent 80%);
    animation: trs-sweep-c-b-trrj0o93c9 8s ease-in-out infinite;
}

@keyframes trs-sweep-a-b-trrj0o93c9 {
    0%, 100% { transform: translateX(-50%) rotate(-22deg); }
    50% { transform: translateX(-50%) rotate(16deg); }
}

@keyframes trs-sweep-b-b-trrj0o93c9 {
    0%, 100% { transform: translateX(-50%) rotate(20deg); }
    50% { transform: translateX(-50%) rotate(-14deg); }
}

@keyframes trs-sweep-c-b-trrj0o93c9 {
    0%, 100% { transform: translateX(-50%) rotate(4deg); }
    50% { transform: translateX(-50%) rotate(-30deg); }
}

/* ── podium ─────────────────────────────────────────────────────────────── */
.trs-podium[b-trrj0o93c9] {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1.15fr 1fr;
    align-items: end;
    gap: 16px;
    max-width: 760px;
    margin: 0 auto;
    padding: 0 20px;
}

.trs-spot[b-trrj0o93c9] {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 0;
    /* Bronze lights up first, then silver, then the champion. */
    animation: trs-lightup-b-trrj0o93c9 0.8s ease backwards;
}

.trs-p3[b-trrj0o93c9] { animation-delay: 0.1s; }
.trs-p2[b-trrj0o93c9] { animation-delay: 0.45s; }
.trs-p1[b-trrj0o93c9] { animation-delay: 0.8s; }

@keyframes trs-lightup-b-trrj0o93c9 {
    from { opacity: 0; filter: brightness(0.2); }
    to { opacity: 1; filter: none; }
}

.trs-pair[b-trrj0o93c9] {
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

/* The figures overlap slightly so a pair reads as one group, and are pulled down over the block's top
   edge by the empty space the SVG leaves below the feet. ::deep because the class rides on
   PodiumFigure's own root span, which carries that component's scope attribute rather than this page's. */
.trs-pair[b-trrj0o93c9]  .pf.trs-fig {
    width: 98px;
    margin-bottom: -13px;
    /* Rim light, so the athletes read against the dark stage without a pool of light on the floor. */
    filter: drop-shadow(0 0 14px rgba(255, 255, 255, 0.26));
}

.trs-pair[b-trrj0o93c9]  .pf.trs-fig + .pf.trs-fig {
    margin-left: -18px;
}

/* Kit colours per place, consumed by PodiumFigure's own scoped rules via these custom properties. */
.trs-p1[b-trrj0o93c9] { --pf-kit: #e3b341; --pf-kit-d: #9a6b00; }
.trs-p2[b-trrj0o93c9] { --pf-kit: #8fa0b0; --pf-kit-d: #5d6a76; }
.trs-p3[b-trrj0o93c9] { --pf-kit: #c07b3a; --pf-kit-d: #7c4a1e; }

.trs-p1[b-trrj0o93c9]  .pf.trs-fig {
    animation: trs-cheer-b-trrj0o93c9 2.4s ease-in-out 1.8s infinite;
}

@keyframes trs-cheer-b-trrj0o93c9 {
    0%, 100% { transform: translateY(0); }
    45% { transform: translateY(-8px); }
}

/* The block carries the place and the roster. Content is bottom-aligned so the plaques sit the same
   distance off the floor on all three; the champion's extra height reads as headroom above the number. */
.trs-block[b-trrj0o93c9] {
    position: relative;
    width: 100%;
    border-radius: 10px 10px 0 0;
    padding: 11px 10px 14px;
    text-align: center;
    color: white;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.45), 0 -6px 30px rgba(0, 0, 0, 0.35);
}

.trs-no[b-trrj0o93c9] {
    display: block;
    font-size: 27px;
    font-weight: 900;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}

/* min-height rather than a fixed height: a category with three- or four-player teams simply grows the
   plaque, and the grid's align-items:end keeps every block sitting on the same floor. */
.trs-p1 .trs-block[b-trrj0o93c9] {
    background: linear-gradient(180deg, #e3b341 0%, #9a6b00 100%);
    min-height: 158px;
}

.trs-p2 .trs-block[b-trrj0o93c9] {
    background: linear-gradient(180deg, #9aa7b4 0%, #66727e 100%);
    min-height: 132px;
}

.trs-p3 .trs-block[b-trrj0o93c9] {
    background: linear-gradient(180deg, #c07b3a 0%, #7c4a1e 100%);
    min-height: 114px;
}

.trs-p1 .trs-no[b-trrj0o93c9] {
    font-size: 32px;
}

/* The champion's block breathes a gold halo. */
.trs-p1 .trs-block[b-trrj0o93c9]::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 10px 10px 0 0;
    animation: trs-halo-b-trrj0o93c9 2.6s ease-in-out 1.6s infinite;
}

@keyframes trs-halo-b-trrj0o93c9 {
    0%, 100% { box-shadow: 0 0 0 0 rgba(227, 179, 65, 0.45); }
    50% { box-shadow: 0 0 26px 6px rgba(227, 179, 65, 0.55); }
}

/* The roster sits directly on the coloured block — no plaque behind it, no rule above it. */
.trs-plate[b-trrj0o93c9] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 10px;
    padding: 0 10px;
}

.trs-plate .trs-team-name[b-trrj0o93c9] {
    font-size: 12px;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.85);
    text-align: center;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

/* PlayerLabel is built for a light surface; on the podium block it needs the inverse. These are contextual
   overrides of the shared component (not a copy of it) — the name flips to the block's white bold type from
   the design, and the rating track to a translucent white so the bar still reads against gold/silver/bronze.
   ::deep because the markup belongs to PlayerLabel's scope, not this page's. */
.trs-plate[b-trrj0o93c9]  .player-label.trs-player {
    text-align: center;
}

.trs-plate[b-trrj0o93c9]  .player-label-name {
    font-size: 13.5px;
    font-weight: 800;
    line-height: 1.4;
    color: white;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.trs-p1 .trs-plate[b-trrj0o93c9]  .player-label-name {
    font-size: 14.5px;
}

.trs-plate[b-trrj0o93c9]  .player-label-bar {
    background: rgba(255, 255, 255, 0.32);
}

/* ── confetti cannons ───────────────────────────────────────────────────── */
.trs-cannon[b-trrj0o93c9] {
    position: absolute;
    bottom: 0;
    width: 50%;
    height: 100%;
    pointer-events: none;
    overflow: hidden;
    z-index: 3;
}

.trs-cannon-l[b-trrj0o93c9] { left: 0; }
.trs-cannon-r[b-trrj0o93c9] { right: 0; }

.trs-cannon i[b-trrj0o93c9] {
    position: absolute;
    bottom: 8px;
    width: 8px;
    height: 13px;
    border-radius: 2px;
    opacity: 0;
    background: var(--trs-cc);
    animation: trs-burst-b-trrj0o93c9 var(--trs-cdur) cubic-bezier(0.15, 0.7, 0.5, 1) var(--trs-cd) infinite;
}

.trs-cannon-l i[b-trrj0o93c9] { left: 8px; }
.trs-cannon-r i[b-trrj0o93c9] { right: 8px; }

@keyframes trs-burst-b-trrj0o93c9 {
    0% { opacity: 0; transform: translate(0, 0) rotate(0); }
    6% { opacity: 1; }
    100% { opacity: 0; transform: translate(var(--trs-cx), var(--trs-cy)) rotate(680deg); }
}

/* ── 4th and below ──────────────────────────────────────────────────────── */
.trs-list[b-trrj0o93c9] {
    list-style: none;
    margin: 2rem auto 0;
    padding: 0 12px 2rem;
    max-width: 720px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.trs-row[b-trrj0o93c9] {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 10px 14px;
    background: white;
    border: 1px solid var(--border-color, #e2e6ea);
    border-radius: 10px;
}

.trs-rank[b-trrj0o93c9] {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    min-width: 2.2rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted, #6c757d);
}

.trs-team[b-trrj0o93c9] {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.trs-team-name[b-trrj0o93c9] {
    font-weight: 600;
}

/* Roster: one PlayerLabel per player, side by side. Each label gets the same 170px track so the rating
   bars underneath the names are directly comparable down the standings; they wrap on a narrow row. */
.trs-players[b-trrj0o93c9] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    min-width: 0;
}

/* Fixed (not shrinkable) track: the list is content-sized, so a shrinkable basis would collapse each label
   to its own name's width and the bars would no longer share a scale. ::deep because the class rides on
   PlayerLabel's own root span, which carries that component's scope attribute rather than this page's. */
.trs-players[b-trrj0o93c9]  .player-label.trs-player {
    flex: 0 0 170px;
}

@media (max-width: 640px) {
    .trs-podium[b-trrj0o93c9] {
        gap: 6px;
        padding: 0 10px;
    }

    .trs-pair[b-trrj0o93c9]  .pf.trs-fig {
        width: 64px;
    }

    .trs-pair[b-trrj0o93c9]  .pf.trs-fig + .pf.trs-fig {
        margin-left: -12px;
    }

    .trs-no[b-trrj0o93c9],
    .trs-p1 .trs-no[b-trrj0o93c9] {
        font-size: 23px;
    }

    .trs-plate[b-trrj0o93c9] {
        padding: 0;
    }
}

/* Vestibular safety: the celebration is decorative — the place, names and ratings are all static text —
   so every looping animation stops and the confetti is removed outright. */
@media (prefers-reduced-motion: reduce) {
    .trs-beam[b-trrj0o93c9],
    .trs-p1[b-trrj0o93c9]  .pf.trs-fig,
    .trs-p1 .trs-block[b-trrj0o93c9]::after,
    .trs-cannon i[b-trrj0o93c9] {
        animation: none;
    }

    .trs-cannon[b-trrj0o93c9] {
        display: none;
    }

    .trs-spot[b-trrj0o93c9] {
        animation-duration: 0.01ms;
        animation-delay: 0s;
    }
}
/* /Pages/TournamentSchedulePage.razor.rz.scp.css */
/* The viewport-locked page shell (column-flex frame + the shared height-chain
   plumbing) lives in app.css on `.app-viewport-locked`, which this page's root
   carries. This file only styles the schedule's own toolbar and timeline. */

/* Fixed single-strip header (.ts-row1): the preview link and player search grow
   from the left, the spacer pushes Regenerate/Start to the right. Never scrolls
   out of view. */
.ts-toolbar[b-e02u35sfmi] {
    border-bottom: 1px solid var(--border-color, #e2e6ea);
    background: #fff;
}

/* The action strip: preview link + search on the left, the spacer pushes
   Regenerate/Start to the right; wraps button-by-button when narrow. */
.ts-row1[b-e02u35sfmi] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    padding: 8px 12px;
}

.ts-spacer[b-e02u35sfmi] {
    flex: 1 1 auto;
}

/* The `.as-form-field` variant in app.css stretches the search group to
   width:100%, so this wrapper owns the sizing: floored at 220px (a comfortable
   minimum for player/team names) and capped so it never hogs the strip — the
   .ts-spacer, not the search, absorbs the free space on wide screens. */
.ts-search[b-e02u35sfmi] {
    flex: 0 1 340px;
    min-width: 220px;
    max-width: 340px;
}

/* Empty-state banner needs its own breathing room — the locked layout drops
   the layout's content padding. */
.ts-empty[b-e02u35sfmi] {
    padding: 12px;
}

/* The fixed-width sticky court column adopts a rotated court-name spine beside the group strips while
   reorganising — that layout now lives in the timeline's own scoped CSS (.tl-grouped-header), shared by
   this page and the live board. This page only sets --ts-courtw inline on .ts-timeline (computed from the
   busiest court's group count); the gantt inherits it.

   The timeline claims all remaining height via .app-scroll-region (app.css) and sits flush to every edge
   — no border or radius in the locked layout. */
/* /Pages/TournamentsGridPage.razor.rz.scp.css */
.draft-hint[b-ba28ltkagf] {
    margin: 0 0 1rem;
    font-size: .82rem;
    color: #5b7280;
}

.draft-grid[b-ba28ltkagf] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: .75rem;
}

.draft-card[b-ba28ltkagf] {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding: .9rem 1rem;
    border: 1px solid var(--border-color, #e2e6ea);
    border-radius: 10px;
    background: #fff;
    text-decoration: none;
    color: #5b7280;
    filter: grayscale(1);
    transition: border-color .15s ease, transform .15s ease;
}

.draft-card:hover[b-ba28ltkagf] {
    border-color: #5b7280;
    transform: translateY(-1px);
}

.draft-badge[b-ba28ltkagf] {
    align-self: flex-start;
    padding: .1rem .5rem;
    border-radius: 999px;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    background: #e2e6ea;
    color: #5b7280;
}

.draft-title[b-ba28ltkagf] {
    margin: 0;
}

.draft-meta[b-ba28ltkagf] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .75rem;
    font-size: .82rem;
}

.draft-date[b-ba28ltkagf] {
    font-weight: 600;
}

.draft-location[b-ba28ltkagf]::before {
    content: "· ";
}
/* /Pages/TournamentSimulationPage.razor.rz.scp.css */
/* Keeps the clock-warning pinned while the tournament list scrolls. */
.tsim-warning[b-psr4i1q1tw] {
    position: sticky;
    top: 0.5rem;
    z-index: 10;
    margin-bottom: 0.5rem;
}

.tsim-panel[b-psr4i1q1tw] {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    width: 100%;
}

.tsim-intro[b-psr4i1q1tw],
.tsim-empty[b-psr4i1q1tw] {
    color: var(--text-muted, #6b7280);
    margin: 0;
}

.tsim-section-title[b-psr4i1q1tw] {
    margin: 0;
}

.tsim-tournaments[b-psr4i1q1tw] {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

/* Each tournament is one pressable card; picking it opens the modal run dialog. */
.tsim-tournament[b-psr4i1q1tw] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    width: 100%;
    padding: 0.6rem 0.9rem;
    border: 1px solid var(--border, #d1d5db);
    border-radius: 0.5rem;
    background: var(--surface, #ffffff);
    cursor: pointer;
    text-align: left;
    font: inherit;
}

.tsim-tournament:hover[b-psr4i1q1tw] {
    border-color: var(--border-strong, #9ca3af);
}

.tsim-tournament-main[b-psr4i1q1tw] {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.tsim-tournament-name[b-psr4i1q1tw] {
    font-weight: 600;
}

.tsim-tournament-summary[b-psr4i1q1tw] {
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
}

.tsim-tournament-meta[b-psr4i1q1tw] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.tsim-state[b-psr4i1q1tw] {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: var(--surface-muted, #f3f4f6);
    color: var(--text-muted, #6b7280);
}

.tsim-state-open[b-psr4i1q1tw] {
    background: var(--success-bg, #dcfce7);
    color: var(--success, #16a34a);
}

.tsim-state-started[b-psr4i1q1tw] {
    background: var(--danger-bg, #fee2e2);
    color: var(--danger, #dc2626);
}

.tsim-date[b-psr4i1q1tw] {
    color: var(--text-muted, #6b7280);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}
