:root {
    --primary: #182B49;
    --primary-light: #00629B;
    --accent: #FFCD00;
    --secondary-accent: #00C6D7;

    --background: #F5F7FA;
    --surface: #FFFFFF;
    --surface-alt: #EEF1F5;

    --text: #182B49;
    --text-muted: #53657A;

    --border: #D9DEE5;
    --radius: 8px;
}

/* System preference applies only when the visitor hasn't made an explicit
   choice (see the toggle script in layouts/public.blade.php, which sets
   data-theme and persists it in localStorage). */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --primary: #081522;
        --primary-light: #00629B;
        --accent: #FFCD00;
        --secondary-accent: #00C6D7;

        --background: #0D1B2A;
        --surface: #182B49;
        --surface-alt: #203A56;

        --text: #FFFFFF;
        --text-muted: #AAB7C4;

        --border: #30465C;
    }
}

:root[data-theme="dark"] {
    --primary: #081522;
    --primary-light: #00629B;
    --accent: #FFCD00;
    --secondary-accent: #00C6D7;

    --background: #0D1B2A;
    --surface: #182B49;
    --surface-alt: #203A56;

    --text: #FFFFFF;
    --text-muted: #AAB7C4;

    --border: #30465C;
}

* { box-sizing: border-box; }

body {
    margin: 0;
    /* .page-header-bleed's 100vw breakout counts the scrollbar itself as
       part of the viewport width, so it overshoots the real content area
       by the scrollbar's width on any page tall enough to need one -
       this hides that sliver rather than letting it force its own
       horizontal scrollbar. */
    overflow-x: hidden;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--background);
    color: var(--text);
    line-height: 1.5;
}

h1, h2, h3 {
    font-weight: 700;
}

/*
 * Triton Blue reads fine on the light background, but it's too close in
 * luminance to dark mode's navy card/page surfaces to stand out as a
 * link - Cyan (already the "active/current" accent) has real contrast
 * against navy instead, so it takes over as the link color there.
 */
a { color: var(--primary-light); text-decoration: none; }
a:hover { text-decoration: underline; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) a { color: var(--secondary-accent); }
}

:root[data-theme="dark"] a { color: var(--secondary-accent); }

/*
 * Sticks to the top on scroll - the scoreboard banner above it does not,
 * so it scrolls away normally and the header takes over the top of the
 * viewport once you've scrolled past it.
 */
.site-header {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--primary);
    color: #fff;
}

.site-header .bar {
    max-width: 1100px;
    margin: 0 auto;
    padding: 14px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
}

.site-header .brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 1.25rem;
    font-weight: 700;
    color: #fff;
}

/*
 * The header bar is a dark navy in BOTH themes (see .site-header below -
 * --primary is #182B49 in light mode, #081522 in dark mode, neither of
 * which is actually light), so the logo (a single solid-black mark) is
 * flattened to solid white unconditionally rather than switching per
 * theme - there's no "light" header background to ever show its real
 * black ink against.
 */
.brand-logo {
    height: 64px;
    width: auto;
    filter: brightness(0) invert(1);
}

.site-header .bar-right {
    display: flex;
    align-items: center;
    gap: 16px;
}

.site-header nav {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
}

/* > (direct child) rather than a plain descendant selector - otherwise
   this also matches the Statistics/Info dropdown panels' own links
   (nested under nav > details > div > a) and its light header-bar colors
   override that panel's own (correctly white-surface-aware) color rules
   via higher specificity, since .nav-dropdown-panel a has one fewer
   element in its selector. */
.site-header nav > a {
    color: #dce8f5;
    font-size: 0.92rem;
    font-weight: 500;
}

.site-header nav > a:hover {
    color: var(--secondary-accent);
}

.site-header nav > a.active {
    color: var(--secondary-accent);
}

/* Hidden on desktop entirely - only relevant once .site-header nav
   itself collapses into a toggled panel below (see the mobile block at
   the bottom of this file). */
.nav-toggle {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 30px;
    height: 30px;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
}

.nav-toggle-bar {
    display: block;
    width: 100%;
    height: 2px;
    background: #fff;
    border-radius: 1px;
    transition: transform 0.15s ease, opacity 0.15s ease;
}

/* The 3 bars collapse into an X once the menu is open, rather than a
   separate icon swap. */
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) {
    opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
}

.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.3);
    color: #dce8f5;
    border-radius: 999px;
    cursor: pointer;
    font-family: inherit;
    flex-shrink: 0;
}

.theme-toggle:hover {
    color: #fff;
    border-color: var(--secondary-accent);
}

.nav-dropdown {
    position: relative;
}

.nav-dropdown summary {
    cursor: pointer;
    color: #dce8f5;
    font-size: 0.92rem;
    font-weight: 500;
    list-style: none;
}

.nav-dropdown summary::-webkit-details-marker { display: none; }

.nav-dropdown summary::after {
    content: '▾';
    margin-left: 4px;
    font-size: 0.7rem;
}

.nav-dropdown summary:hover {
    color: var(--secondary-accent);
}

.nav-dropdown summary.active {
    color: var(--secondary-accent);
}

.nav-dropdown-panel {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    min-width: 220px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 6px;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}

.nav-dropdown-panel a {
    color: var(--text);
    padding: 7px 10px;
    border-radius: 4px;
    font-size: 0.9rem;
}

.nav-dropdown-panel a:hover,
.nav-dropdown-panel a.active {
    background: var(--surface-alt);
    color: var(--primary-light);
    text-decoration: none;
}

@media (max-width: 760px) {
    .nav-dropdown-panel {
        position: static;
        box-shadow: none;
        margin-top: 4px;
    }
}

@media (max-width: 760px) {
    /* .brand and .bar-right stay on the same top row; the hamburger
       button (inside .bar-right) toggles nav onto its own full-width
       row below via flex-basis, rather than nav ever sharing the top
       row with the brand logo. */
    .site-header .brand { order: 1; }
    .site-header .bar-right { order: 2; }
    .site-header nav { order: 3; }

    .nav-toggle {
        display: flex;
    }

    .site-header nav {
        display: none;
        flex-direction: column;
        align-items: flex-start;
        flex-basis: 100%;
        width: 100%;
        gap: 2px;
        padding-top: 10px;
        border-top: 1px solid rgba(255, 255, 255, 0.15);
    }

    .site-header nav.is-open {
        display: flex;
    }

    .site-header nav > a,
    .nav-dropdown summary {
        padding: 8px 0;
        width: 100%;
    }
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 24px 20px 60px;
}

.container-wide {
    max-width: 1600px;
}

.page-title {
    margin: 0 0 20px;
    font-size: 1.6rem;
}

.breadcrumbs {
    margin-bottom: 10px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
    opacity: 0.7;
}

.breadcrumbs a { color: var(--text-muted); }
.breadcrumbs a:hover { color: var(--primary-light); text-decoration: underline; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .breadcrumbs a:hover { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .breadcrumbs a:hover { color: var(--secondary-accent); }

.breadcrumbs-sep {
    margin: 0 6px;
    color: var(--border);
}

.breadcrumbs-current {
    display: inline-block;
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
    color: var(--text);
}

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
    margin-bottom: 20px;
    /* Nearly every table on the site sits inside a .card - scrolling the
       card horizontally (rather than letting the table squish its
       columns down to fit) is what actually makes a wide table usable on
       a phone, paired with table's own white-space:nowrap below. */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.card h2 {
    margin-top: 0;
    font-size: 1.1rem;
    border-bottom: 1px solid var(--border);
    padding-bottom: 10px;
}

/* Star of the Week (public/home.blade.php) - the photo floats to the
   right with the name/team/description text wrapping around it, rather
   than a fixed two-column row. */
.star-feature::after {
    content: '';
    display: table;
    clear: both;
}

.star-photo {
    display: block;
    float: right;
    margin-left: 16px;
    margin-bottom: 8px;
    width: 120px;
    height: 120px;
    object-fit: cover;
    border-radius: var(--radius);
    border: 1px solid var(--border);
}

/* The homepage's own Star of the Week is the single featured pick, so
   it gets a larger photo than the shared .star-photo base size. */
.star-photo-lg {
    width: auto;
    max-height: 325px;
    height: auto;
}

.star-feature-text .player-name {
    display: block;
    font-size: 1.35rem;
}

.star-feature-team {
    margin: 2px 0 8px;
    font-size: 0.9rem;
    color: var(--text-muted);
}

/* A right-floated 240px photo leaves little room for text on a narrow
   screen - stack it full-width above the text instead. */
@media (max-width: 480px) {
    .star-photo {
        float: none;
        margin-left: 0;
        width: 100%;
        height: auto;
        aspect-ratio: 1 / 1;
    }
}

.grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}

.grid-3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}

/* News page (public/news.blade.php) - Weekly Recaps at 2/3 width,
   Star of the Week at 1/3, alongside it. */
.grid-news {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 20px;
    align-items: start;
}

@media (max-width: 760px) {
    .grid-2, .grid-3, .grid-news { grid-template-columns: 1fr; }
}

/* Each recap card: a fixed-size image on the left, excerpt/"Read More"
   on the right - the same media-object shape as .home-recap-list-item,
   just roomier since these are full cards rather than a compact list. */
.news-recap-card {
    display: flex;
    gap: 16px;
}

.news-recap-image {
    width: 160px;
    height: 160px;
    object-fit: cover;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    flex-shrink: 0;
}

.news-recap-text {
    flex: 1 1 auto;
    min-width: 0;
}

.news-recap-text h2 {
    margin: 4px 0 10px;
}

@media (max-width: 480px) {
    .news-recap-card {
        flex-direction: column;
    }

    .news-recap-image {
        width: 100%;
        height: auto;
        aspect-ratio: 16 / 9;
    }
}

/* Compact Star of the Week list (no photo) - just the name/team line and
   description, stacked one after another in a single card. */
.news-star-item {
    padding-bottom: 14px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

.news-star-item:last-child {
    padding-bottom: 0;
    margin-bottom: 0;
    border-bottom: none;
}

.news-star-meta {
    margin: 2px 0 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.news-star-description {
    margin-top: 4px;
    font-size: 0.9rem;
    color: var(--text-muted);
}

/*
 * Teams page cards - a colored left bar (the team's own swatch color),
 * fixed to the same size for every card regardless of roster length, so
 * a card's position in the grid never shifts when expanded. "Players"
 * swaps the whole body's content (see .team-card-collapsed/-expanded)
 * rather than growing the card - only one of the two is visible at a
 * time (public/js/team-cards.js toggles their [hidden] attributes), and
 * a long roster scrolls inside the fixed-height card instead of pushing
 * it taller.
 */
.team-card {
    height: 220px;
    padding: 14px 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 10px solid var(--border);
    border-radius: var(--radius);
    overflow-y: auto;
    scrollbar-width: thin;
    scroll-margin-top: 16px;
}

.team-card::-webkit-scrollbar { width: 6px; }
.team-card::-webkit-scrollbar-track { background: transparent; }
.team-card::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }

.team-card-collapsed:not([hidden]) {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.team-card-name {
    margin: 0 0 6px;
    font-size: 1.1rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.01em;
}

.team-card-name-long {
    font-size: 0.92rem;
}

.team-card-name a { color: var(--primary-light); }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .team-card-name a { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .team-card-name a { color: var(--secondary-accent); }

.team-card-record {
    margin: 0 0 8px;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
}

.team-card-captain {
    margin: 0 0 4px;
    font-size: 0.9rem;
}

.team-card-actions {
    display: flex;
    gap: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

.team-card-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 7px 14px;
    border: none;
    border-radius: 6px;
    background: var(--primary);
    color: #fff;
    font-size: 0.85rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}

.team-card-btn:hover {
    background: var(--primary-light);
    text-decoration: none;
}

/* Players index header search (public/players-index.blade.php) - styled
   to sit inside the same page-header-bleed section as the page title and
   stat boxes, rather than the plain unstyled form it used to be. */
.players-search {
    display: flex;
    gap: 8px;
    margin-top: 16px;
}

.players-search-input {
    flex: 1 1 auto;
    max-width: 320px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    font-size: 0.9rem;
    font-family: inherit;
}

.players-search-input:focus {
    outline: none;
    border-color: var(--primary-light);
}

.players-search-btn {
    padding: 8px 16px;
    border: none;
    border-radius: var(--radius);
    background: var(--primary);
    color: #fff;
    font-weight: 600;
    font-size: 0.9rem;
    font-family: inherit;
    cursor: pointer;
}

.players-search-btn:hover {
    background: var(--primary-light);
}

/* A small thumbnail next to a player's name in the Players list table
   (public/players-index.blade.php) - unstyled, an <img> renders at its
   real upload size and blows out the row/table layout. */
.player-list-photo {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    object-fit: cover;
    vertical-align: middle;
    margin-right: 6px;
}

/* Show/hide optional columns on a table with a lot of them (see the
   player profile page's season-by-season tables and public/js/column-
   toggle.js) - a row of pill buttons rather than a text filter, since
   the "too much info" problem here is column count, not row count. */
.column-toggle {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 10px;
}

.column-toggle-label {
    margin-right: 4px;
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
}

.column-toggle-btn {
    padding: 4px 10px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-muted);
    font-size: 0.78rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}

.column-toggle-btn.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

/* Pagination sits in the same row as the search box above the table
   (left/right), and on its own right-aligned row below it. */
.players-list-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 16px;
}

.players-list-header .players-search {
    margin-top: 0;
}

.players-list-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 16px;
}

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
}

.pagination-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
}

a.pagination-item:hover {
    background: var(--surface-alt);
    text-decoration: none;
}

.pagination-current {
    background: var(--primary);
    color: #fff;
}

.pagination-disabled {
    color: var(--text-muted);
    opacity: 0.5;
}

/*
 * :not([hidden]) - not just .team-card-expanded - because a bare class
 * selector here would have the same specificity as (and load after) the
 * browser default "[hidden] { display: none }" rule and win, permanently
 * overriding it, leaving this visible at all times regardless of the
 * [hidden] attribute team-cards.js toggles.
 */
.team-card-expanded:not([hidden]) {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
}

.team-card-close {
    position: absolute;
    top: -6px;
    right: 0;
    border: none;
    background: none;
    color: var(--text-muted);
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
}

.team-card-close:hover { color: var(--text); }

.team-card-roster {
    flex: 1;
    list-style: none;
    margin: 8px 0 0;
    padding: 8px 0 0;
    border-top: 1px solid var(--border);
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-content: start;
    gap: 6px 14px;
    font-size: 0.92rem;
}

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
    /* Lets a wide table overflow its .card (which scrolls, see above)
       instead of wrapping cell text and squishing every column down to
       an unreadable width on a phone - width:100% above still applies
       normally whenever the content actually fits. */
    white-space: nowrap;
}

th, td {
    text-align: left;
    padding: 7px 10px;
    border-bottom: 1px solid var(--border);
}

th {
    color: var(--text-muted);
    font-weight: 600;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

tr:hover td { background: var(--surface-alt); }

.num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

/*
 * Sortable stats tables (see public/js/sortable-table.js) - a sortable
 * header shows a neutral double-arrow until clicked, then a single arrow
 * pointing the direction it's currently sorted.
 */
th[data-sort] {
    cursor: pointer;
    user-select: none;
}

th[data-sort]:hover { color: var(--text); }

th[data-sort]::after {
    content: '\21C5';
    margin-left: 5px;
    font-size: 0.7rem;
    opacity: 0.5;
}

th[data-sort][data-sort-direction="asc"]::after { content: '\2191'; opacity: 1; }
th[data-sort][data-sort-direction="desc"]::after { content: '\2193'; opacity: 1; }

/* :not([hidden]) - see the note on .team-card-expanded further down for
   why a bare class selector here would permanently defeat the [hidden]
   attribute this button is toggled with (see sortable-table.js). */
.stats-table-show-more:not([hidden]) {
    display: block;
    margin: 10px 0 24px;
    padding: 8px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--primary-light);
    font-size: 0.88rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}

.stats-table-show-more:hover {
    background: var(--surface-alt);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .stats-table-show-more { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .stats-table-show-more { color: var(--secondary-accent); }

.badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    background: var(--border);
    color: var(--text-muted);
}

/* "Final" is just a status, not a result - gold is reserved for the
   winning score itself (see .score-winner) so it stays special rather
   than appearing on every completed game's badge. */
.badge.final { background: var(--surface-alt); color: var(--primary); }
.badge.upcoming { background: rgba(0, 98, 155, 0.12); color: var(--primary-light); }

/*
 * A gold bubble with its own white text reads fine regardless of the
 * surrounding background (light or dark) - gold text directly on a
 * light surface, with no background of its own, doesn't.
 */
.score-winner {
    display: inline-block;
    background: var(--accent);
    color: #fff;
    font-weight: 700;
    padding: 1px 8px;
    border-radius: 999px;
}

.team-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
    margin-right: 6px;
    vertical-align: middle;
}

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

.season-picker {
    margin-bottom: 20px;
    font-size: 0.92rem;
}

.season-picker select {
    padding: 4px 8px;
    border-radius: 4px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
}

.empty-state {
    color: var(--text-muted);
    font-style: italic;
    padding: 10px 0;
}

/*
 * Shared by any detail page's full-width header banner (box score, team
 * page) - full-bleed to the browser window's edges (not just
 * .container's own max-width) and flush against whatever sits above it,
 * the classic "100vw + negative centering margin" breakout, with a
 * matching negative top margin to cancel out .container's own top
 * padding so there's no gap before it. Each page's own inner content
 * class (.boxscore-header, .team-header, ...) stays constrained to the
 * normal content width so it still lines up with the rest of the page.
 */
.page-header-bleed {
    width: 100vw;
    margin-left: calc(-50vw + 50%);
    margin-right: calc(-50vw + 50%);
    margin-top: -24px;
    margin-bottom: 24px;
    padding-top: 24px;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--border);
}

/* The team page's own color bar (see .team-header-bar) replaces this
   plain border along the bottom edge instead. */
.team-header-bleed {
    border-bottom: none;
}

/* Box score page (public/games-show.blade.php) */
.boxscore-header {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px 24px;
    display: grid;
    grid-template-columns: 1fr minmax(420px, 600px);
    grid-template-areas:
        "crumb crumb"
        "info status";
    align-items: center;
    gap: 8px 24px;
}

.boxscore-header-breadcrumb {
    grid-area: crumb;
}

.boxscore-header-info {
    grid-area: info;
    min-width: 0;
}

/* min-width: 0 overrides a grid item's own default of min-width: auto,
   which otherwise sizes it to fit its content's full intrinsic width
   (the scoreboard table, given team names/white-space:nowrap) no matter
   how narrow its track is - without this, that forces the whole header
   (and the page itself) wider than the viewport on mobile instead of
   letting .card's own overflow-x: auto scroll it in place. */
.boxscore-header-status {
    grid-area: status;
    min-width: 0;
}

.boxscore-header-status .card {
    margin-bottom: 0;
}

.boxscore-header .breadcrumbs {
    color: var(--text-muted);
}

.boxscore-meta {
    margin: 0 0 10px;
    font-size: 0.95rem;
    line-height: 1.8;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.boxscore-title {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    line-height: 1.4;
}

.boxscore-title-team {
    font-size: 1.5rem;
}

.boxscore-title-team .team-swatch {
    margin-left: 4px;
}

.boxscore-title-vs {
    display: block;
    margin-bottom: 4px;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-muted);
}

/*
 * Tablet/medium screens (e.g. a portrait iPad at 768-834px, or a
 * downsized laptop window) still have plenty of width for the 2-column
 * grid's minmax(420, 600) status track alone, but that leaves the info
 * track only 200-300px - not enough room for the meta line or team
 * names, which wrap badly rather than resizing gracefully. Stack the
 * header full-width well before the narrower 760px breakpoint (used
 * elsewhere on this page) actually requires it.
 */
@media (max-width: 1024px) {
    .boxscore-header {
        grid-template-columns: 1fr;
        grid-template-areas:
            "crumb"
            "info"
            "status";
    }

    /* Shot Summary / Goaltender Summary - same reasoning as the header
       above: two tables side by side still technically fit at tablet
       widths, but each gets squeezed too narrow to read comfortably. */
    .boxscore-summary-grid {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 760px) {
    /* flex-basis: 0 with no min-width just squeezes all three star
       cards into one cramped row rather than ever wrapping - stack them
       full-width instead on a narrow screen. */
    .boxscore-stars {
        flex-direction: column;
    }
}

/*
 * Matches .score-winner's own horizontal padding even when it's NOT the
 * winning total, so the digits themselves line up between the two team
 * rows - otherwise the winner's bubble padding shifts its number away
 * from where the loser's plain (unpadded) total sits in the same column.
 */
.boxscore-total {
    display: inline-block;
    padding: 1px 8px;
}

.boxscore-scorer {
    display: block;
    font-weight: 600;
}

.boxscore-assist {
    display: block;
    font-size: 0.82rem;
    color: var(--text-muted);
}

.boxscore-goal-type {
    margin-left: 4px;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .boxscore-goal-type { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .boxscore-goal-type { color: var(--secondary-accent); }

.boxscore-penalties {
    background: var(--surface-alt);
}

.boxscore-penalties .empty-state,
.boxscore-scoring .empty-state {
    text-align: center;
}

.boxscore-stars {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.boxscore-star-card {
    flex: 1 1 0;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px;
}

.boxscore-star-photo-wrap {
    position: relative;
    width: 96px;
    height: 96px;
    margin: 0 auto 10px;
}

.boxscore-star-photo {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.boxscore-star-photo-placeholder {
    background: var(--surface-alt);
}

.boxscore-star-badge {
    position: absolute;
    bottom: -4px;
    right: -4px;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 2px solid var(--surface);
    background: var(--accent);
    color: var(--primary);
    font-weight: 800;
    font-size: 0.85rem;
}

.boxscore-star-name {
    margin: 4px 0 2px;
    font-weight: 700;
}

/* Team page (public/teams-show.blade.php) - same full-bleed .page-header-
   bleed banner as the box score page, with the team's own swatch color as
   a bar along the bottom edge instead of a border/box-shadow of its own. */
.team-header {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px 24px;
}

.team-header-name {
    margin: 12px 0 20px;
    font-size: 2rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    color: var(--text);
}

.team-header-bar {
    height: 6px;
}

/* Player profile page (public/players-show.blade.php) - same full-bleed
   .page-header-bleed banner as the team/schedule/stats pages, with the
   player's own photo (or a placeholder) on the right rather than a
   color bar, since there's no single team color to represent them. */
.player-header {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px 24px;
    display: flex;
    align-items: stretch;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 24px;
}

.player-header-info {
    flex: 1 1 320px;
    min-width: 0;
}

.player-header-name {
    margin: 12px 0 8px;
    font-size: 2rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.01em;
    color: var(--text);
}

.player-bio-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0 0 20px;
    color: var(--text-muted);
    font-size: 0.92rem;
}

.player-bio-meta span:not(:last-child)::after {
    content: '\00b7';
    margin-left: 6px;
    color: var(--border);
}

/* Square (not circular), matching the header's own height (see
   .player-header's align-items: stretch) rather than a fixed size -
   aspect-ratio keeps the width equal to whatever that stretched height
   ends up being, so it's always a true square regardless of how tall
   the name/stats column next to it grows. The negative margins cancel
   out .page-header-bleed's own padding-top (24px) and this row's own
   padding-bottom (24px) - since a stretched flex item's margin box
   still fills the line, this pulls the image edge-to-edge with the
   bleed band itself (acting like the header's own background) instead
   of sitting inset within the same padding the text column keeps. */
.player-header-photo,
.player-header-photo-placeholder {
    width: auto;
    height: 100%;
    aspect-ratio: 1 / 1;
    margin-top: -24px;
    margin-bottom: -24px;
    border-radius: 0;
    border: 1px solid var(--border);
    flex-shrink: 0;
}

.player-header-photo {
    object-fit: cover;
}

.player-header-photo-placeholder {
    background: var(--surface-alt);
}

/* A stretched flex item with no sibling on its own wrapped line (see
   .player-header's flex-wrap) has nothing to stretch against and would
   otherwise collapse to zero height - back to a fixed square size (and
   the bleed margins dropped, since there's no shared row height left to
   bleed against) once the header wraps to a stacked mobile layout. */
@media (max-width: 760px) {
    .player-header-photo,
    .player-header-photo-placeholder {
        width: 140px;
        height: 140px;
        margin-top: 0;
        margin-bottom: 0;
    }
}

/* Career totals row at the bottom of a player's season-by-season stats
   table (see partials/player-season-*-stats.blade.php) - a <tfoot> row,
   so sortable-table.js (which only touches tBodies[0]) never reorders it
   away from the bottom. */
.totals-row td {
    border-top: 2px solid var(--border);
    border-bottom: none;
    font-weight: 700;
    color: var(--text);
}

/* Teams index page (public/teams-index.blade.php) - the same .page-
   header-bleed banner as the team/box score pages, just without a
   breadcrumb (it's a main nav page, not a detail page) or color bar
   (there's no single team to represent here). */
.teams-index-header,
.schedule-index-header,
.standings-index-header,
.playoffs-index-header,
.stats-index-header,
.news-index-header {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
}

/* A season's own logo (Teams/Standings/Stats pages, when one is on
   file - see Season::logoUrl()) sits to the right of the header's own
   title/stats, vertically centered against them via the row's own
   align-items: center above. */
/* One-off: the real team "REDACTED" (Fall 2026's spy-themed season)
   reads as an actual censorship bar on the public site - see
   public/js/team-redact.js for how this class gets applied. */
.team-name-redacted {
    background: #000;
    color: #000 !important;
    border-radius: 2px;
    padding: 0 4px;
    user-select: none;
}

.index-header-logo {
    max-height: 100px;
    width: auto;
    height: auto;
    flex-shrink: 0;
}

/* Same technique as .brand-logo - a season logo is typically dark ink
   on a transparent background, which disappears against the dark
   surfaces this header band switches to in dark mode. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .index-header-logo { filter: brightness(0) invert(1); }
}
:root[data-theme="dark"] .index-header-logo { filter: brightness(0) invert(1); }

.teams-index-header .page-title,
.schedule-index-header .page-title,
.standings-index-header .page-title,
.playoffs-index-header .page-title,
.stats-index-header .page-title,
.news-index-header .page-title {
    margin: 12px 0 16px;
    font-size: 2rem;
    text-transform: uppercase;
    letter-spacing: 0.01em;
}

.schedule-index-header .tabs-nav {
    margin-top: 4px;
}

.schedule-title-row {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}

/* :not([hidden]) since the Standings header toggles two of these
   (season/playoff summaries) via [data-tab-panel] - a bare display:flex
   here would otherwise beat the browser's own [hidden]{display:none}
   rule, same as .schedule-quicknav did. */
.team-hero-stats:not([hidden]) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 24px;
}

.teams-index-swatches {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.teams-index-swatch {
    width: 18px;
    height: 18px;
    border-radius: 5px;
    border: 1px solid var(--border);
    transition: transform 0.1s ease;
}

.teams-index-swatch:hover {
    transform: scale(1.15);
}

.team-hero-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.team-hero-stat-label {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.team-hero-stat-value {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--text);
}

/* The leader's raw stat (e.g. "(14)") next to their name on the Stats
   pages' Goals/Points/Assists/Wins/Save %/GAA leader boxes - de-
   emphasized since the name is the headline and the number is context. */
.team-hero-stat-value-sub {
    margin-left: 4px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-muted);
}

.team-schedule-row {
    display: grid;
    grid-template-columns: 130px 1fr auto;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
    color: var(--text);
}

.team-schedule-row:last-child { border-bottom: none; }
.team-schedule-row:hover { background: var(--surface-alt); text-decoration: none; }

.team-schedule-datetime {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.team-schedule-date {
    font-size: 0.85rem;
    color: var(--text-muted);
}

.team-schedule-week {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.team-schedule-opponent { display: flex; align-items: center; gap: 6px; font-weight: 600; }

.team-schedule-result {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.team-schedule-win { color: #37b24d; }
.team-schedule-loss { color: #f03e3e; }

/* Tablet: the datetime block becomes its own full-width header row above
   opponent/result, since 130px is too tight once the week line is added
   - but there's still not enough width for opponent name + result side
   by side, so the name is dropped in favor of just the swatch. */
@media (max-width: 760px) {
    .team-schedule-row {
        grid-template-columns: 1fr auto;
        grid-template-areas:
            "datetime datetime"
            "opponent result";
        row-gap: 6px;
    }

    .team-schedule-datetime {
        grid-area: datetime;
        flex-direction: row;
        justify-content: space-between;
        padding-bottom: 6px;
        border-bottom: 1px solid var(--border);
    }

    .team-schedule-opponent { grid-area: opponent; }
    .team-schedule-result { grid-area: result; }
    .team-schedule-opponent-name { display: none; }
}

/* Mobile: back to a single stacked column - full width means the
   opponent name fits again, so it's restored. */
@media (max-width: 480px) {
    .team-schedule-row {
        grid-template-columns: 1fr;
        grid-template-areas:
            "datetime"
            "opponent"
            "result";
    }

    .team-schedule-opponent-name { display: inline; }
}

.site-footer {
    color: var(--text-muted);
    font-size: 0.85rem;
    padding: 30px 20px;
    border-top: 1px solid var(--border);
}

.site-footer-inner {
    max-width: 1100px;
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 24px;
}

.site-footer-about {
    max-width: 360px;
}

.site-footer-brand {
    display: block;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
}

.site-footer-about p {
    margin: 0;
}

.site-footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: 24px 48px;
}

.site-footer-col {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 160px;
}

.site-footer-links a {
    color: var(--text-muted);
}

.site-footer-links a:hover {
    color: var(--primary-light);
    text-decoration: underline;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .site-footer-links a:hover {
        color: var(--secondary-accent);
    }
}

:root[data-theme="dark"] .site-footer-links a:hover {
    color: var(--secondary-accent);
}

@media (max-width: 700px) {
    .site-footer-inner {
        flex-direction: column;
    }
}

/*
 * Hidden until scrolled past a screen's worth of content (see the
 * scroll listener in layouts/public.blade.php), rather than always
 * visible.
 */
.back-to-top {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 20;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 999px;
    background: var(--primary);
    color: #fff;
    font-size: 1.2rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.15s ease, visibility 0.15s ease;
}

.back-to-top:hover {
    background: var(--primary-light);
    text-decoration: none;
}

.back-to-top.is-visible {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}

.week-heading {
    margin: 26px 0 10px;
    font-size: 1rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.week-heading:first-child { margin-top: 0; }

.player-name { font-weight: 600; }

.score-line { font-weight: 700; font-size: 1.4rem; }

.period-box {
    display: inline-block;
    min-width: 22px;
    text-align: center;
    padding: 2px 4px;
    border: 1px solid var(--border);
    border-radius: 4px;
    margin-right: 3px;
    font-size: 0.8rem;
}

/*
 * Sits above the site's own header, on every public page (see
 * layouts/public.blade.php + AppServiceProvider's view composer) - picked
 * week/season set from the admin dashboard's Scoreboard widget, not
 * derived automatically. Stretches full-width (outside .container's
 * max-width), with each game given equal flex so the row always fills
 * that width rather than clumping to one side.
 */
.scoreboard-banner {
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    font-size: 0.85rem;
}

.scoreboard-banner-label {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 20px;
    background: var(--surface-alt);
    flex-shrink: 0;
}

.scoreboard-banner-date {
    color: var(--text-muted);
    font-size: 0.78rem;
}

.scoreboard-banner-week {
    font-weight: 700;
    color: var(--text);
    white-space: nowrap;
}

.scoreboard-banner-games {
    display: flex;
    flex-wrap: wrap;
    flex: 1 1 auto;
}

/*
 * A 2-column grid (team name, score) rather than two independent flex
 * rows - team names of different lengths would otherwise push each
 * row's score to a different horizontal position; sharing one grid's
 * column tracks keeps both scores lined up in the same column.
 */
.scoreboard-banner-game {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    flex: 1 1 150px;
    gap: 2px 12px;
    padding: 8px 20px;
    border-left: 1px solid var(--border);
    color: var(--text);
    min-width: 150px;
}

.scoreboard-banner-game:hover {
    background: var(--surface-alt);
    text-decoration: none;
}

.scoreboard-banner-team {
    color: var(--primary-light);
    font-weight: 600;
}

:root[data-theme="dark"] .scoreboard-banner-team { color: var(--secondary-accent); }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .scoreboard-banner-team { color: var(--secondary-accent); }
}

/*
 * Matches .score-winner's own horizontal padding even when it's NOT a
 * winning score, so the digits themselves line up - otherwise the
 * winner's bubble padding shifts its number left of where a plain
 * (unpadded) score in the other row would sit at the same column edge.
 */
.scoreboard-banner-score {
    text-align: right;
    justify-self: end;
    padding: 1px 8px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

@media (max-width: 760px) {
    /* The global ticker eats a lot of vertical space above the fold on a
       phone for what's a nice-to-have on desktop - each page's own
       schedule/box score already covers the same games. */
    .scoreboard-banner { display: none; }
}

/*
 * The one heading style for every "here's the table/section below" label
 * sitewide (Schedule week groups, Standings/Stats page titles, game
 * summary sections, team page Runners/Goaltending/Substitutes, playoff
 * bracket groups) - kept as a single class so changing the look in one
 * place keeps every page consistent, rather than each page inventing its
 * own heading weight/size.
 */
.schedule-section-title {
    margin: 32px 0 12px;
    font-size: 0.95rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.schedule-section-title:first-of-type {
    margin-top: 0;
}

/* Team page - this heading sits directly in the page's own content flow
   (not nested inside a tab panel like the other schedule-section-title
   headings above it), so it's :first-of-type within its own parent and
   would otherwise get margin-top:0 from the rule above. */
.team-schedule-title {
    margin-top: 40px;
}

.team-schedule-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.team-schedule-heading .team-schedule-title {
    margin-bottom: 0;
}

.calendar-subscribe-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--primary-light);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 999px;
    flex-shrink: 0;
    white-space: nowrap;
}

.calendar-subscribe-link svg {
    flex-shrink: 0;
}

.calendar-subscribe-link:hover {
    background: var(--surface-alt);
    text-decoration: none;
}

/* :not([hidden]) rather than a bare .schedule-quicknav{display:flex} -
   otherwise this same-specificity author rule permanently beats the
   browser's own [hidden]{display:none} UA rule, so the tab this row
   belongs to would stay visible even while marked hidden (see the same
   fix on .team-card-collapsed/-expanded and .stats-table-show-more). */
.schedule-quicknav:not([hidden]) {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 20px;
}

.schedule-quicknav a {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    padding: 8px 18px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

.schedule-quicknav a:hover {
    background: var(--surface-alt);
    border-color: var(--primary-light);
}

.schedule-week-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin: 30px 0 14px;
    padding-bottom: 10px;
    border-bottom: 2px solid var(--primary);
}

.schedule-week-header:first-of-type {
    margin-top: 0;
}

.schedule-week-title {
    margin: 0;
    font-size: 1.3rem;
}

.schedule-week-meta {
    color: var(--text-muted);
    font-size: 0.95rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.schedule-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    margin-bottom: 10px;
}

.schedule-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px;
}

.schedule-card-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

/*
 * Blue reads fine on the card's light surface, but (like body links -
 * see the `a` rule near the top) is too close in luminance to a dark
 * surface to stay visible there, so it switches to Cyan in dark mode.
 */
.schedule-card-time {
    font-weight: 700;
    color: var(--text);
}

/*
 * A shared 3-column grid (swatch, team info, score) across both team
 * rows, rather than two independent flex rows - team names of different
 * lengths would otherwise push each row's score to a different
 * horizontal position; sharing one grid's column tracks keeps both
 * scores lined up in the same column (same technique as the scoreboard
 * banner's own game cards).
 */
.schedule-card-teams {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 6px 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

.schedule-card-teams .team-swatch {
    width: 6px;
    height: 28px;
    border-radius: 3px;
    margin: 0;
}

.schedule-card-team-info {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
}

.schedule-card-team-label {
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.schedule-card-team-name {
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.schedule-card-team-name-winner {
    font-weight: 700;
    color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .schedule-card-team-name-winner { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .schedule-card-team-name-winner { color: var(--secondary-accent); }

/*
 * Matches .score-winner's own horizontal padding even when it's NOT a
 * winning score, so the digits themselves line up - otherwise the
 * winner's bubble padding shifts its number left of where a plain
 * (unpadded) score in the other row would sit at the same column edge.
 */
.schedule-card-score {
    text-align: right;
    justify-self: end;
    padding: 1px 8px;
    font-size: 1.15rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.schedule-card-officials {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
    font-size: 0.78rem;
    color: var(--text-muted);
}

/* Box score header card (public/games-show.blade.php) has room to keep
   Scorekeeper and Referees on one line rather than stacked. */
.schedule-card-officials-inline {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 16px;
}

.schedule-card-officials-label {
    text-transform: uppercase;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    margin-right: 4px;
}

.schedule-card-cta {
    display: block;
    text-align: center;
    background: var(--accent);
    color: var(--primary);
    font-weight: 700;
    padding: 10px;
    border-radius: 6px;
    margin-top: auto;
}

.schedule-card-cta:hover {
    text-decoration: none;
    filter: brightness(0.95);
}

/* The navy text (--primary) that reads fine on the gold button in light
   mode looks muddy against it in dark mode, where every other accent
   already swaps to a lighter color against dark surfaces. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .schedule-card-cta { color: #fff; }
}
:root[data-theme="dark"] .schedule-card-cta { color: #fff; }

/* A pre-scheduled bracket-reset game that turned out not to be needed
   (see Game::isNotNeeded()) - no box score to view, so this isn't a
   clickable link at all, just a plain label in its place. */
.schedule-card-cta-disabled {
    display: block;
    text-align: center;
    background: var(--surface-alt);
    color: var(--text-muted);
    font-weight: 700;
    padding: 10px;
    border-radius: 6px;
    margin-top: auto;
}

/*
 * Grid/List layout toggle (public/schedule.blade.php) - both
 * .schedule-card-grid and .schedule-line-list are always rendered for
 * every week (see schedule-week-card.blade.php), and #schedule-view-root's
 * own [data-view] attribute (set by schedule-view-toggle.js, persisted in
 * localStorage) just shows one and hides the other - no re-render needed
 * to switch, same "pre-render both, toggle visibility" approach already
 * used for the Season/Playoffs tabs on this same page.
 */
.schedule-line-list {
    display: none;
}

#schedule-view-root[data-view="line"] .schedule-card-grid {
    display: none;
}

#schedule-view-root[data-view="line"] .schedule-line-list {
    display: flex;
    flex-direction: column;
    margin-bottom: 10px;
}

.schedule-title-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.schedule-view-toggle {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 2px;
    flex-shrink: 0;
}

.schedule-view-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-muted);
    background: transparent;
    border: none;
    border-radius: 999px;
    cursor: pointer;
}

.schedule-view-btn:hover {
    color: var(--text);
}

.schedule-view-btn-active {
    background: var(--surface-alt);
    color: var(--text);
}

/* One full-width row per game - each game's own time, matchup, status,
   and box score link laid out in a single line rather than the grid
   layout's stacked card, so a whole week reads as a scannable list. Any
   scorekeeper/referee info (see .schedule-line-officials) sits as its
   own line underneath rather than crowding the main line. */
.schedule-line-row {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: none;
}

.schedule-line-row:first-child {
    border-top: 1px solid var(--border);
    border-radius: var(--radius) var(--radius) 0 0;
}

.schedule-line-row:last-child {
    border-radius: 0 0 var(--radius) var(--radius);
}

.schedule-line-row:first-child:last-child {
    border-radius: var(--radius);
}

.schedule-line-main {
    display: grid;
    grid-template-columns: 70px 1fr auto 120px;
    align-items: center;
    gap: 16px;
}

.schedule-line-cta {
    margin-top: 0;
}

.schedule-line-officials {
    padding-top: 8px;
    border-top: 1px solid var(--border);
}

.schedule-line-time {
    font-weight: 700;
    color: var(--text);
    font-size: 0.9rem;
}

.schedule-line-matchup {
    display: grid;
    grid-template-columns: auto 1fr auto auto auto 1fr auto;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.schedule-line-matchup .team-swatch {
    width: 6px;
    height: 22px;
    border-radius: 3px;
    margin: 0;
}

.schedule-line-team {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.schedule-line-team-away {
    text-align: right;
}

.schedule-line-team-winner {
    font-weight: 700;
    color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .schedule-line-team-winner { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .schedule-line-team-winner { color: var(--secondary-accent); }

.schedule-line-score {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
    min-width: 1.5em;
}

.schedule-line-sep {
    color: var(--text-muted);
}

@media (max-width: 760px) {
    .schedule-line-main {
        grid-template-columns: 1fr;
        row-gap: 8px;
    }

    /* Falls back to a plain 3-column grid (swatch/name/score) with the
       browser's own default row-major auto-flow - .schedule-line-sep is
       hidden (below) and removed from flow entirely, so the remaining 6
       children land exactly as two rows of three: away's swatch/name/
       score, then home's score/name/swatch. */
    .schedule-line-matchup {
        grid-template-columns: auto 1fr auto;
        row-gap: 4px;
    }

    .schedule-line-team-away { text-align: left; }
    .schedule-line-sep { display: none; }
}

/*
 * Playoff Bracket (see public/playoffs.blade.php) - a horizontal flow of
 * round-columns (each round narrows down to fewer matches, reading
 * left-to-right like a real bracket tree). Rounds share the row's width
 * evenly (flex: 1 1 0) rather than a fixed column width, so the Winners
 * bracket stretches to fill the page's own (wide) container and every
 * round is visible without scrolling on a normal desktop width - the
 * min-width plus overflow-x:auto below is only a fallback for a screen
 * too narrow to fit them all.
 */
.bracket {
    display: flex;
    align-items: stretch;
    gap: 16px;
    overflow-x: auto;
    padding-bottom: 10px;
}

.bracket-round {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 12px;
    flex: 1 1 0;
    min-width: 190px;
}

/* Only used by the irregular-team-count (week-grouped) fallback view now -
   the real Winners/Losers/Finals bracket rounds render with no title. */
.bracket-round-title {
    margin: 0;
    padding-bottom: 8px;
    font-size: 1rem;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
}

/*
 * A leaner, purpose-built matchup card for the bracket page - a thin meta
 * row (date + status/score-link) over two team rows, rather than reusing
 * the taller .schedule-card grid component (with its Away/Home labels
 * and full-size CTA button) - short enough that a 4-match first round
 * fits one screen's height, and every round in the row shares its column
 * width evenly (see .bracket-round) rather than a fixed narrow width.
 */
.bracket-matchup {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

/* The whole card is the click target (see bracket-matchup.blade.php's
   .bracket-matchup-link overlay) rather than a small button, so this is
   just the hover affordance. */
.bracket-matchup-clickable:hover {
    border-color: var(--primary-light);
}

.bracket-matchup-link {
    position: absolute;
    inset: 0;
}

.bracket-matchup-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 5px 10px;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--border);
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
}

.bracket-matchup-status {
    font-weight: 700;
    color: var(--text-muted);
}

.bracket-matchup-status-final {
    color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .bracket-matchup-status-final { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .bracket-matchup-status-final { color: var(--secondary-accent); }

.bracket-matchup-team {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    font-size: 0.85rem;
}

.bracket-matchup-team + .bracket-matchup-team {
    border-top: 1px solid var(--border);
}

.bracket-matchup-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Matches .score-winner's own pill padding even when NOT the winner, so
   the digits themselves line up regardless of which side won (same
   pattern as .schedule-card-score/.boxscore-total). */
.bracket-matchup-score {
    display: inline-block;
    padding: 1px 8px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.bracket-matchup-team-winner .bracket-matchup-name {
    font-weight: 700;
    color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .bracket-matchup-team-winner .bracket-matchup-name { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .bracket-matchup-team-winner .bracket-matchup-name { color: var(--secondary-accent); }

/*
 * The Finals sit beside the Winners bracket (not stacked below it) - both
 * are "the top line" of a double-elimination bracket, with the Losers
 * bracket as its own full-width row underneath. bracket-group grows to
 * fill the row (so the Winners bracket stretches the full page width);
 * bracket-group-finals stays fixed to its own content width and
 * vertically centers in the row so it lines up near the Winners
 * bracket's own final round regardless of how many rounds came before it.
 */
.bracket-top-row {
    display: flex;
    align-items: center;
    gap: 40px;
    flex-wrap: wrap;
}

.bracket-group {
    flex: 1 1 auto;
    min-width: 0;
}

.bracket-group-finals {
    flex: 0 0 220px;
}

/*
 * Generic click-to-switch tabs (see public/js/tabs.js) - used on the team
 * page for the Season/Playoffs/Substitutes stats group and the
 * Season/Playoffs schedule group. Each [data-tab-group] is scoped on its
 * own, so target names ("season", "playoffs") can repeat across groups
 * on the same page.
 */
.tabs-nav {
    display: flex;
    gap: 4px;
    margin-bottom: 16px;
    border-bottom: 1px solid var(--border);
}

.tabs-btn {
    padding: 10px 16px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    font: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-muted);
    cursor: pointer;
}

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

.tabs-btn-active {
    color: var(--primary-light);
    border-bottom-color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .tabs-btn-active { color: var(--secondary-accent); border-bottom-color: var(--secondary-accent); }
}

:root[data-theme="dark"] .tabs-btn-active { color: var(--secondary-accent); border-bottom-color: var(--secondary-accent); }

/*
 * Home page (public/home.blade.php) - the latest published recap acts as
 * a real featured-post hero. Both the eyebrow/title and the image/
 * excerpt/body below share the same centered, max-width content column
 * every other index page's own header uses (see .stats-index-header
 * etc.), for every image_layout - only the .page-header-bleed band's own
 * background runs the full width of the page.
 */
.home-feature-header {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px 24px;
}

.home-feature {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px 32px;
}

.home-feature-image {
    display: block;
    width: 100%;
    border-radius: var(--radius);
    background: var(--surface);
    border: 1px solid var(--border);
}

/*
 * .home-feature-media always holds the image directly followed by the
 * excerpt (see .home-feature-excerpt below) - grouping them together
 * means the excerpt reliably renders right under the image in every
 * layout, including the wrap/side-by-side ones, since it's just normal
 * block flow inside this one shared box rather than living next to the
 * body text. Only .home-feature-text (the body) actually moves around
 * relative to the image between layouts.
 */

/*
 * Full Width (default, and what every layout falls back to for a recap
 * with no image at all) - the image+excerpt sit above the body as their
 * own full-width band. object-fit: contain (not cover) so a real
 * uploaded photo's own proportions are never cropped.
 */
.home-feature-layout-full .home-feature-media {
    margin-bottom: 20px;
}

.home-feature-layout-full .home-feature-image {
    height: auto;
    max-height: 600px;
    object-fit: contain;
}

/*
 * Left/Right, Text Wraps Around - the image+excerpt float together as
 * one unit, with the body flowing around it like a magazine layout. The
 * clearfix keeps the bleed band's own background from collapsing to
 * zero height when the floated block is taller than the body beside it.
 */
.home-feature-layout-left-wrap .home-feature-media,
.home-feature-layout-right-wrap .home-feature-media {
    width: 420px;
    max-width: 55%;
    margin-bottom: 16px;
}

.home-feature-layout-left-wrap .home-feature-media {
    float: left;
    margin-right: 28px;
}

.home-feature-layout-right-wrap .home-feature-media {
    float: right;
    margin-left: 28px;
}

.home-feature-layout-left-wrap .home-feature-image,
.home-feature-layout-right-wrap .home-feature-image {
    height: 280px;
    object-fit: cover;
}

.home-feature-layout-left-wrap::after,
.home-feature-layout-right-wrap::after {
    content: '';
    display: table;
    clear: both;
}

/*
 * Left/Right, No Wrap - a fixed two-column row: the image+excerpt stay
 * their own column and the body column never flows underneath them.
 * row-reverse puts that column on the right for that variant, while the
 * markup order stays the same either way.
 */
.home-feature-layout-left,
.home-feature-layout-right {
    display: flex;
    gap: 32px;
    align-items: flex-start;
    flex-wrap: wrap;
}

.home-feature-layout-right {
    flex-direction: row-reverse;
}

.home-feature-layout-left .home-feature-media,
.home-feature-layout-right .home-feature-media {
    flex: 0 0 440px;
    width: 440px;
}

.home-feature-layout-left .home-feature-image,
.home-feature-layout-right .home-feature-image {
    height: 340px;
    object-fit: cover;
}

.home-feature-layout-left .home-feature-text,
.home-feature-layout-right .home-feature-text {
    flex: 1 1 340px;
    min-width: 0;
}

.home-feature-label {
    display: block;
    margin-bottom: 8px;
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.home-feature-title {
    margin: 0 0 14px;
    font-size: 1.9rem;
}

/*
 * A pull-quote treatment (accent rule + italic) sets the excerpt apart
 * from the body text. excerpt is rich HTML (same RichEditor field type
 * as body - see WeeklyRecapForm and public/news.blade.php's own {!! !!}
 * rendering of it), typically just a single wrapped <p>, so its own
 * paragraph margin is zeroed out in favor of this margin instead.
 */
.home-feature-excerpt {
    margin: 12px 0 0;
    padding-left: 14px;
    border-left: 3px solid var(--primary-light);
    font-size: 0.92rem;
    font-style: italic;
    line-height: 1.55;
    color: var(--text-muted);
}

.home-feature-excerpt p {
    margin: 0;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .home-feature-excerpt { border-left-color: var(--secondary-accent); }
}
:root[data-theme="dark"] .home-feature-excerpt { border-left-color: var(--secondary-accent); }

/* The recap's full body is raw admin-authored HTML (WYSIWYG, or migrated
   straight from WordPress) - it isn't wrapped in the site's normal
   heading/paragraph rhythm, so this gives it baseline prose spacing for
   whatever mix of tags a given recap happens to contain. */
.home-feature-full-body {
    margin: 0;
    font-size: 1rem;
    line-height: 1.75;
}

.home-feature-full-body p {
    margin: 0 0 16px;
}

.home-feature-full-body h1,
.home-feature-full-body h2,
.home-feature-full-body h3,
.home-feature-full-body h4 {
    margin: 24px 0 12px;
    line-height: 1.3;
}

.home-feature-full-body ul,
.home-feature-full-body ol {
    margin: 0 0 16px;
    padding-left: 24px;
}

.home-feature-full-body li {
    margin-bottom: 6px;
}

.home-feature-full-body blockquote {
    margin: 0 0 16px;
    padding-left: 14px;
    border-left: 3px solid var(--border);
    color: var(--text-muted);
    font-style: italic;
}

.home-feature-full-body img {
    max-width: 100%;
    border-radius: var(--radius);
}

.home-feature-full-body a {
    text-decoration: underline;
}

/*
 * Upcoming Games keeps its full-bleed background across the ENTIRE
 * section (header + the card grid itself, via the nested
 * .home-section-content wrapper) - League Leaders reuses the same
 * .home-section-header markup directly in the page's own flow, with no
 * bleed wrapper at all, so only one of the two sections carries a
 * background band.
 */
.home-section-bleed {
    width: 100vw;
    margin-left: calc(-50vw + 50%);
    margin-right: calc(-50vw + 50%);
    margin-top: 8px;
    margin-bottom: 24px;
    padding: 24px 0;
    background: var(--surface-alt);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
}

.home-section-content {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 20px;
}

.home-section-header {
    max-width: 1200px;
    margin: 0 auto 20px;
    padding: 0 20px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.home-section-bleed .home-section-header {
    margin-bottom: 16px;
}

/* All-caps, the site's established "winner/accent" color pairing
   (primary-light in light mode, secondary-accent in dark - see
   .schedule-card-team-name-winner for the same convention), and a touch
   smaller than a normal <h2> so it reads as a section label rather than
   a heading in its own right. */
.home-section-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--primary-light);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .home-section-title { color: var(--secondary-accent); }
}
:root[data-theme="dark"] .home-section-title { color: var(--secondary-accent); }

.home-section-link {
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
}

.home-recap-list {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.home-recap-list-item {
    display: flex;
    gap: 12px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

.home-recap-list-item:last-child {
    padding-bottom: 0;
    border-bottom: none;
}

.home-recap-list-image {
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    flex-shrink: 0;
}

.home-recap-list-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.home-recap-list-title {
    display: block;
    font-weight: 600;
}

.home-recap-list-meta {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
}

/* excerpt is rich HTML (see WeeklyRecapForm's RichEditor) - clamped to 2
   lines so a long excerpt can't blow out this compact list layout. */
.home-recap-list-excerpt {
    font-size: 0.85rem;
    color: var(--text-muted);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.home-recap-list-excerpt p {
    margin: 0;
}

/* Equal-height Standings/Scoring Leaders/Goalie Leaders cards - grid's
   own default (align-items: stretch) already sizes every card in the
   row to the tallest one, this just makes sure each card's own content
   fills that box (flex column) and pins its trailing "Full stats" link
   to the same bottom edge across all three regardless of how many rows
   its own table has above it. */
.home-leaders-grid {
    align-items: stretch;
}

.home-leaders-grid .card {
    display: flex;
    flex-direction: column;
    margin-bottom: 0;
}

.home-leaders-more {
    margin-top: auto;
    padding-top: 12px;
}

/* Every layout collapses to the same simple stacked full-width look on
   a narrow screen - there's no room left for a floated or side-by-side
   image at that width. */
@media (max-width: 760px) {
    .home-feature-layout-left-wrap .home-feature-media,
    .home-feature-layout-right-wrap .home-feature-media,
    .home-feature-layout-left .home-feature-media,
    .home-feature-layout-right .home-feature-media {
        float: none;
        width: 100%;
        max-width: none;
        flex-basis: 100%;
        margin: 0 0 16px;
    }

    .home-feature-layout-full .home-feature-image,
    .home-feature-layout-left-wrap .home-feature-image,
    .home-feature-layout-right-wrap .home-feature-image,
    .home-feature-layout-left .home-feature-image,
    .home-feature-layout-right .home-feature-image {
        height: 160px;
    }

    .home-feature-layout-left,
    .home-feature-layout-right {
        flex-direction: column;
    }
}
