html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

h1:focus {
    outline: none;
}

a, .btn-link {
    color: #0071c1;
}

/* Bootstrap colours inactive tab (.nav-link) text with its default link blue
   (#0d6efd), which doesn't match the site palette. Align it to our link/green. */
.nav-tabs {
    --bs-nav-link-color: #0071c1;
    --bs-nav-link-hover-color: #004A33;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
    /* Breathing room so the last element on a page isn't flush against the bottom edge. */
    padding-bottom: 2.5rem;
}

/* Score table: the page becomes a viewport-tall flex column so ONLY the table
   region scrolls (one scrollbar, not two), and its header freezes at the top —
   so on a small screen you keep track of which column is which while scrolling. */
/* Make the whole shell a viewport-tall flex column while the score page is mounted,
   so ONLY the table region scrolls (one scrollbar, not two) and the sticky header
   stays put. Scoped with :has() so it applies only on the score page and needs no
   magic offset — MainLayout banners (pending-apps / unpaid) above @Body just take
   their space and the table region fills what's left (a fixed 100dvh − Nrem calc
   didn't account for those banners and reintroduced the double scrollbar). */
.page:has(.score-page) {
    height: 100dvh;
    overflow: hidden;
}
.page:has(.score-page) main {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
}
/* Only the grid region gives up space; everything above it keeps its natural height.
   As flex items in the column these default to flex-shrink:1, so once the riders
   loaded and the column wanted more than 100dvh, the browser took the difference out
   of the 3.5rem top row — it loaded correct, then visibly shrank and went cramped. */
.page:has(.score-page) .top-row,
.page:has(.score-page) .content > .alert {
    flex: 0 0 auto;
}
.page:has(.score-page) .content {
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    overflow: hidden;
    /* The article must itself be a flex column, or .score-page's flex sizing
       is inert and the overflow simply CLIPS - no scrollbar at all. */
    display: flex;
    flex-direction: column;
}
.score-page {
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* The grid below switches to cards on the width IT has, not the window's. Keyed
       to the viewport it broke twice over: the sidebar returns at 641px, so between
       641 and 700 you got the sidebar AND cards squeezed into a narrow column; and
       above 700 the table came back even when the sidebar had left it no room. */
    container: wsc-score / inline-size;
}
.score-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
}
/* Ringside quick-add strip. Sits below .score-scroll (never inside it) so it stays
   on screen at any scroll position and its typeahead lists aren't clipped by the
   grid's overflow. Collapsed behind a button by default — see _addOpen. */
.score-addbar {
    border-top: 1px solid #dee2e6;
    padding-top: 0.5rem;
}
.score-addfield {
    min-width: 10rem;
    flex: 0 1 12rem;
}

/* Scoring on a phone: the grid has up to a dozen columns, so the generic
   scroll-sideways rule below left you seeing Rider/Horse and nothing else — you
   couldn't score without dragging each row back and forth. Under 700px each row
   becomes a CARD instead: rider name as its heading, then one labelled line per
   field. Labels come from each cell's data-label, so the per-discipline columns
   carry across on their own. */
@container wsc-score (max-width: 700px) {
    /* table.score-grid, not .score-grid: the generic "wide tables scroll sideways"
       rule later in this file is also (0,1,0) and would otherwise win on order,
       putting white-space:nowrap back on the cards. */
    table.score-grid {
        display: block;
        overflow-x: visible;
        white-space: normal;
    }
    table.score-grid thead { display: none; }
    table.score-grid tbody,
    table.score-grid tr,
    table.score-grid td { display: block; width: auto; }

    table.score-grid tr {
        border: 1px solid #dee2e6;
        border-radius: 0.5rem;
        margin-bottom: 0.6rem;
        padding: 0.5rem 0.7rem;
        background: #fff;
    }
    table.score-grid td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.75rem;
        border: 0;
        padding: 0.25rem 0;
        text-align: left !important;
    }
    table.score-grid td::before {
        content: attr(data-label);
        font-size: 0.8rem;
        font-weight: 600;
        color: #6c757d;
        flex: 0 0 auto;
    }
    /* The rider is the card's title, not another labelled field. */
    table.score-grid td.cell-rider {
        display: block;
        font-size: 1.05rem;
        font-weight: 700;
        border-bottom: 1px solid #eee;
        padding-bottom: 0.4rem;
        margin-bottom: 0.25rem;
    }
    table.score-grid td.cell-rider::before { content: none; }
    /* Controls take the right-hand half so the labels stay in a readable column. */
    table.score-grid td .form-select,
    table.score-grid td .form-control {
        flex: 0 1 58%;
        min-width: 0 !important;
        width: auto;
    }
    /* An empty derived cell (no placing yet) would collapse to just its label. */
    table.score-grid td:empty::after { content: "—"; color: #adb5bd; }

    /* Sub-league / Pos / Pts keep their league tint, but as one rounded block inset
       from the card edge — run full-bleed they read as a rendering fault. */
    table.score-grid td[class*="sl-"] { padding-left: 0.5rem; padding-right: 0.5rem; }
    table.score-grid td[data-label="Sub-league"] {
        border-top-left-radius: 0.35rem;
        border-top-right-radius: 0.35rem;
        margin-top: 0.3rem;
    }
    table.score-grid td[data-label="Pts"] {
        border-bottom-left-radius: 0.35rem;
        border-bottom-right-radius: 0.35rem;
    }

    /* The add panel's fields go full width rather than three cramped columns. */
    .score-addfield { flex: 1 1 100%; min-width: 0; }
    .score-actions .btn { flex: 1 1 auto; }
}
.score-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background-color: #fff;
    box-shadow: inset 0 -2px 0 #dee2e6;
}

/* Sub-league tints for the scoring grid's Pos/Pts cells — bronze/silver/gold
   match the league names; the rest are soft, distinct pastels. */
.sl-bronze { background-color: #e9cfae !important; }
.sl-silver { background-color: #e0e0e0 !important; }
.sl-gold   { background-color: #f7e08a !important; }
.sl-staff  { background-color: #cfdce8 !important; }
.sl-ol     { background-color: #d7e8d4 !important; }
.sl-school { background-color: #e6d9f2 !important; }
.sl-do     { background-color: #cfe8e5 !important; }

/* Past events in the list view — a light grey wash so they read as history
   when shown alongside upcoming ones. */
.event-past {
    background-color: #f1f3f5;
}
.event-past .event-title strong {
    color: #6c757d;
}

/* Device-specific UI. touch-only = phones/tablets, where a file input's capture
   attribute hands off to the native camera app. desktop-only = mouse devices,
   where the camera needs the in-page webcam (getUserMedia) route instead. */
.desktop-only { display: none !important; }
@media (hover: hover) and (pointer: fine) {
    .touch-only { display: none !important; }
    .desktop-only { display: inline-block !important; }
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

/* Club-branded version of Blazor's unhandled-error banner (see index.html).
   Dark green to match the boot screen and the site header, rather than the
   stock lightyellow. color-scheme is pinned so a dark-mode browser can't
   invert the colours we set here. */
#blazor-error-ui {
    color-scheme: light only;
    background: #14342a;
    color: #fff;
    border-top: 3px solid #14663f;
    bottom: 0;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.25);
    box-sizing: border-box;
    display: none;
    font-size: 0.95rem;
    left: 0;
    line-height: 1.5;
    padding: 0.75rem 2.75rem 0.85rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui a {
        color: #9fe0bd;
        font-weight: 600;
    }

    #blazor-error-ui .reload {
        margin-left: 0.5rem;
        white-space: nowrap;
    }

    #blazor-error-ui .dismiss {
        color: #fff;
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}

    .loading-progress circle {
        fill: none;
        stroke: #e0e0e0;
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: #1b6ec2;
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

code {
    color: #c02d76;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ===== Wellington Saddle Club branding ===== */
:root {
    --wsc-green: #004A33;
    --wsc-green-dark: #003322;
    --wsc-green-light: #1f6b50;
}

a, .btn-link { color: var(--wsc-green); }
a:hover { color: var(--wsc-green-dark); }

h1, h2, h3 { color: var(--wsc-green); }

.btn-primary {
    background-color: var(--wsc-green);
    border-color: var(--wsc-green-dark);
}
.btn-primary:hover, .btn-primary:focus, .btn-primary:active {
    background-color: var(--wsc-green-dark) !important;
    border-color: var(--wsc-green-dark) !important;
}
.btn-outline-primary { color: var(--wsc-green); border-color: var(--wsc-green); }
.btn-outline-primary:hover { background-color: var(--wsc-green); border-color: var(--wsc-green); color: #fff; }

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--wsc-green-light);
}

.form-check-input:checked { background-color: var(--wsc-green); border-color: var(--wsc-green); }

table thead th { color: var(--wsc-green); }

.loading-progress circle:last-child { stroke: var(--wsc-green); }

.wsc-login-logo { display: block; max-width: 220px; height: auto; margin: 0 0 1rem; }
.rosette { color: #b8860b; font-weight: 700; }

.login-title { margin: -0.25rem 0 0.75rem; font-weight: 700; }

/* Rich text (Quill) editor for committee minutes. The editable area grows with the
   viewport and scrolls INSIDE itself, so the toolbar (above) and Save buttons (below)
   stay visible on long minutes without the page needing to scroll. The min-height is
   the practical floor on short screens (below which two scrollbars are unavoidable). */
.wsc-rte { max-width: 100%; }
/* The editable area's max-height is set by JS (wscQuill.fit) to the real available
   space; min-height is the floor on short screens. */
.wsc-rte .ql-editor {
    min-height: 10rem;
    overflow-y: auto;
    font-size: 1rem;
}
/* Read-only minutes view scrolls internally too, keeping the Print/Word buttons in view. */
.wsc-rte-view {
    max-height: calc(100vh - 20rem);
    overflow-y: auto;
}
.wsc-rte-view :is(h1,h2,h3) { font-size: 1.15rem; font-weight: 700; margin: .6rem 0 .3rem; }
.wsc-rte-view ul, .wsc-rte-view ol { padding-left: 1.4rem; }
.wsc-rte-view blockquote {
    margin: .5rem 0;
    padding: .25rem 0 .25rem .9rem;
    border-left: 3px solid #ccc;
    color: #555;
}

/* Centre the login / sign-up column on the page. Each block (logo, title, text,
   card) has its own max-width, so margin auto centres them in the content area. */
.auth-page { margin-top: 1.5rem; }
.auth-page > * { margin-left: auto; margin-right: auto; }
.auth-page .login-title { text-align: center; }

.calendar-cell { height: 5.5rem; vertical-align: top; overflow: hidden; }
.calendar-other { background-color: #f8f9fa; }
.calendar-cell a { color: var(--wsc-green); text-decoration: none; }
.calendar-cell a:hover { text-decoration: underline; }

/* Home dashboard — tap tiles for every feature the signed-in user can reach, so
   nothing important is hidden behind the (collapsed-on-mobile) menu. */
.dash-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.75rem;
    max-width: 52rem;
}
.dash-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    text-align: center;
    min-height: 6.5rem;
    padding: 1rem 0.75rem;
    border: 1px solid #e2e2e2;
    border-radius: 0.6rem;
    background: #fff;
    color: var(--wsc-green);
    text-decoration: none;
    box-shadow: 0 1px 2px rgba(0,0,0,.05);
    transition: transform .06s ease, box-shadow .12s ease, border-color .12s ease;
}
.dash-tile:hover, .dash-tile:focus {
    border-color: var(--wsc-green);
    box-shadow: 0 3px 8px rgba(0,0,0,.12);
    color: var(--wsc-green-dark);
    transform: translateY(-1px);
}
.dash-tile:active { transform: translateY(0); }
.dash-icon { font-size: 1.9rem; line-height: 1; }
.dash-label { font-weight: 600; font-size: 0.95rem; }
.dash-tile-admin { background: #f6f9f7; }
.dash-badge { position: absolute; top: 0.5rem; right: 0.5rem; }
.dash-divider {
    display: flex;
    align-items: center;
    text-align: center;
    color: #888;
    margin: 1.5rem 0 0.9rem;
    max-width: 52rem;
}
.dash-divider::before, .dash-divider::after { content: ""; flex: 1; border-bottom: 1px solid #ddd; }
.dash-divider span {
    padding: 0 0.75rem;
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
@media (min-width: 700px) {
    .dash-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Events list rows — robust on narrow phones. Title + badges wrap together on top,
   date/time/type sit on a muted line below, and the action buttons drop to their own
   full-width line rather than squashing into a centred jumble. */
.event-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
}
.event-row-clickable { cursor: pointer; }
.event-main { flex: 1 1 16rem; min-width: 0; }
.event-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 0.5rem;
}
.event-title .badge { font-weight: 600; }
.event-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.1rem 0.6rem;
    margin-top: 0.15rem;
}
.event-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin-left: auto;
}
/* Uniform-width primary buttons so Start list / Score / Minutes align in neat columns
   across rows (the icon-only delete button keeps its natural size). */
.event-actions .btn:not(.btn-link) { min-width: 5.25rem; }
/* Always reserve the trailing delete slot for admins so its presence/absence on a row
   (finalised events have none) doesn't shift the other buttons out of alignment. */
.event-delete-slot {
    flex: 0 0 auto;
    width: 1.1rem;
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
}
@media (max-width: 575.98px) {
    .event-actions { margin-left: 0; width: 100%; }
}

/* Public home / landing page */
.home-hero { position: relative; border-radius: 0.5rem; overflow: hidden; margin-bottom: 1.75rem; }
.home-hero-img { width: 100%; height: 340px; object-fit: cover; display: block; filter: brightness(0.55); }
.home-hero-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; color: #fff; padding: 1rem; }
.home-hero-logo { width: 84px; height: auto; margin-bottom: 0.5rem; background: #fff; border-radius: 50%; padding: 5px; }
.home-hero-title { color: #fff !important; margin: 0; font-weight: 700; }
.home-hero-tagline { font-size: 1.15rem; margin: 0.25rem 0 1.1rem; }
.home-hero-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; justify-content: center; }
.home-section { max-width: 52rem; margin: 0 auto 1.75rem; }

/* Home calendar: let event cells grow and wrap so names are fully readable. */
.home-calendar .calendar-cell { height: auto; min-height: 2.5rem; overflow: visible; padding: 0.35rem 0.5rem; vertical-align: top; }
.home-cal-event { white-space: normal; overflow-wrap: anywhere; line-height: 1.2; }

.login-or { display: flex; align-items: center; text-align: center; color: #888; margin: 1.25rem 0; }
.login-or::before, .login-or::after { content: ""; flex: 1; border-bottom: 1px solid #ddd; }
.login-or span { padding: 0 0.75rem; font-size: 0.85rem; font-weight: 600; }

/* Mobile: let any wide table scroll sideways instead of breaking the layout. */
@media (max-width: 700px) {
    .table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        white-space: nowrap;
    }
    .wsc-login-logo { max-width: 170px; }
}
/* Click-to-sort tables (see wscSortable in interop.js) */
table.js-sortable thead th:not([data-nosort]) {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
table.js-sortable thead th:not([data-nosort]):hover {
    text-decoration: underline;
}
.sort-ind {
    opacity: 0.8;
    font-size: 0.8em;
}
/* Drag-to-reorder handle (start list rows) */
.drag-handle {
    cursor: grab;
    color: #adb5bd;
    touch-action: none; /* let SortableJS own the drag gesture on touch */
    user-select: none;
}
.drag-handle:hover { color: #6c757d; }
.drag-handle:active { cursor: grabbing; }
.sortable-ghost { opacity: 0.4; }
.sortable-chosen { background: #eef4ff; }

/* ComboBox typeahead */
.wsc-combo { position: relative; }
.wsc-combo-list {
    position: absolute;
    z-index: 1050;
    left: 0; right: 0;
    background: #fff;
    border: 1px solid #ced4da;
    border-radius: 0.375rem;
    max-height: 14rem;
    overflow-y: auto;
    box-shadow: 0 0.25rem 0.5rem rgba(0,0,0,.15);
}
.wsc-combo-item {
    padding: 0.35rem 0.75rem;
    cursor: pointer;
    font-size: 0.875rem;
    line-height: 1.4;
}
.wsc-combo-item:hover,
.wsc-combo-item.active {
    background: #1b6ec2;
    color: #fff;
}
.wsc-combo-list-up {
    bottom: 100%;
    top: auto;
}

/* A cancelled event stays in the list — greyed back so it reads as "was on, isn't
   now" rather than competing with the events that are still going ahead. */
.event-cancelled {
    background-color: #f8f9fa;
    opacity: 0.75;
}

/* Test sheet: the live totals card. On desktop the top bar is sticky and
   3.5rem tall, so the card parks just below it instead of sliding underneath;
   on phones the bar scrolls away and the card can hug the top. */
.sheet-totals {
    position: sticky;
    top: 0.5rem;
    z-index: 5;
    max-width: 30rem;
}
@media (min-width: 641px) {
    .sheet-totals { top: 4rem; }
}
