/* ==========================================================================
   CleverPunts components
   ==========================================================================

   Requires cp-tokens.css. Twelve classes, all prefixed cp-.

   THE RULE FOR ADDING ANYTHING HERE
   Before writing a new component, check whether Bootstrap already has one.
   Bootstrap 5.3 is driven by its own CSS variables, so the cheaper move is
   almost always to retheme it through --bs-* (see the bridge at the bottom of
   this file) rather than write a replacement. New classes are for things
   Bootstrap has no equivalent of.

   Names are prefixed because the prototype claimed .card, .badge, .grid and
   .small. There are 1,379 uses of .card across 153 files on this site, all of
   them Bootstrap cards. An unprefixed .card here would restyle every one.
   ========================================================================== */

/* --- Buttons ------------------------------------------------------------ */
/* Every colour rule here is prefixed .cp on purpose. Buttons are usually <a>
   elements, and `.cp a` in cp-base.css is specificity (0,1,1) - it beats a
   bare `.cp-btn--primary` at (0,1,0) and repaints the label with the link
   colour. In dark that is lime on lime: an invisible button. The prototype
   hid this with `color: ...!important`; raising specificity by one class is
   the honest fix and keeps !important out of the system. */

.cp .cp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 47px;
    padding: 10px 21px;
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius);
    background: var(--cp-surface);
    color: var(--cp-ink);
    font-family: inherit;
    font-size: var(--cp-text-base);
    font-weight: 650;
    text-decoration: none;
    cursor: pointer;
}

.cp .cp-btn:hover { border-color: var(--cp-accent-line); }

/* The one place the raw accent is correct: as a fill, with dark ink on it.
   12.7:1 in both themes, so this button needs no light-mode variant. */
.cp .cp-btn--primary {
    background: var(--cp-accent);
    border-color: var(--cp-accent);
    color: var(--cp-on-accent);
}

.cp .cp-btn--quiet {
    background: none;
    border-color: var(--cp-line);
    color: var(--cp-muted);
}

.cp .cp-btn--sm { min-height: 36px; padding: 6px 14px; font-size: var(--cp-text-sm); }

/* --- Page head ---------------------------------------------------------- */
/* The title-and-standfirst block at the top of a tool or content page.
   Replaces the ad-hoc `header-gradient text-white` markup, which asserted a
   literal white and relied on a gradient class that was only ever defined
   inside tools/accumulator/index.php - so on every other page it was a no-op
   and the white text merely inherited a permanently dark site.

   No colour is set on the heading here on purpose: it inherits --cp-ink from
   .cp, which is what makes it correct in both themes. */

.cp-pagehead {
    padding: var(--cp-space-6) 0 var(--cp-space-5);
    border-bottom: 1px solid var(--cp-line);
    margin-bottom: var(--cp-space-6);
}

.cp .cp-pagehead h1 {
    font-size: clamp(30px, 3.4vw, 44px);
    letter-spacing: var(--cp-track-h2);
    margin: 0 0 var(--cp-space-2);
    max-width: none;
}

.cp-pagehead p {
    color: var(--cp-muted);
    margin: 0;
    max-width: 650px;
}

/* --- Surfaces ----------------------------------------------------------- */

.cp-card {
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius-lg);
    padding: 26px;
    background: var(--cp-surface);
}

.cp-card > :last-child { margin-bottom: 0; }
.cp-card p { color: var(--cp-muted); }

.cp-panel {
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius-lg);
    background: var(--cp-surface);
    overflow: hidden;
}

.cp-panel__head {
    padding: 16px 22px;
    border-bottom: 1px solid var(--cp-line);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--cp-space-3);
    font-size: var(--cp-text-sm);
}

.cp-panel__body { padding: var(--cp-space-5) 22px; }

/* --- Labels ------------------------------------------------------------- */

.cp-eyebrow {
    display: block;
    font-size: var(--cp-text-xs);
    letter-spacing: 0.15em;
    font-weight: 700;
    color: var(--cp-accent-ink);
    text-transform: uppercase;
}

.cp-tag {
    display: block;
    font-size: var(--cp-text-xs);
    color: var(--cp-accent-ink);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin-bottom: 9px;
}

.cp-badge {
    display: inline-block;
    padding: 3px 9px;
    border: 1px solid var(--cp-accent-line);
    border-radius: var(--cp-radius-sm);
    font-size: var(--cp-text-xs);
    color: var(--cp-accent-ink);
    letter-spacing: 0.04em;
}

.cp-badge--warn { border-color: var(--cp-warn); color: var(--cp-warn); }
.cp-badge--bad  { border-color: var(--cp-bad);  color: var(--cp-bad); }

/* --- Callout ------------------------------------------------------------ */

.cp-callout {
    padding: 20px 24px;
    border: 1px solid var(--cp-accent-line);
    background: var(--cp-accent-dim);
    border-radius: var(--cp-radius);
    margin: 22px 0;
}

.cp-callout > :last-child { margin-bottom: 0; }

/* --- Numbered steps ----------------------------------------------------- */

.cp-steps {
    list-style: none;
    padding: 0;
    counter-reset: cp-steps;
}

.cp-steps > li {
    position: relative;
    padding: 0 0 28px 54px;
    border-bottom: 1px solid var(--cp-line);
    margin-bottom: 26px;
    counter-increment: cp-steps;
}

.cp-steps > li::before {
    content: counter(cp-steps, decimal-leading-zero);
    position: absolute;
    left: 0;
    top: 0;
    color: var(--cp-accent-ink);
    font-size: 15px;
    font-weight: 700;
}

.cp-steps > li:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.cp-steps p { color: var(--cp-muted); margin-bottom: var(--cp-space-2); }

/* --- Recipe ------------------------------------------------------------- */

.cp-recipe {
    border: 1px solid var(--cp-line);
    background: var(--cp-surface);
    border-radius: var(--cp-radius);
    padding: var(--cp-space-5);
    margin: var(--cp-space-4) 0;
}

.cp-recipe > :last-child { margin-bottom: 0; }
.cp-recipe ul, .cp-recipe ol { padding-left: 23px; margin-bottom: 0; }
.cp-recipe li { margin: 5px 0; }

/* --- Table of contents -------------------------------------------------- */

.cp-toc {
    align-self: start;
    position: sticky;
    top: 25px;
    border-left: 1px solid var(--cp-line);
    padding-left: 20px;
}

.cp-toc a {
    display: block;
    color: var(--cp-muted);
    padding: 6px 0;
    text-decoration: none;
    font-size: var(--cp-text-sm);
}

.cp-toc a:hover,
.cp-toc a[aria-current="true"] { color: var(--cp-accent-ink); }

/* --- Stat strip --------------------------------------------------------- */

.cp-strip {
    display: flex;
    justify-content: space-between;
    gap: 22px;
    border-top: 1px solid var(--cp-line);
    border-bottom: 1px solid var(--cp-line);
    padding: 20px 0;
    flex-wrap: wrap;
    font-size: var(--cp-text-sm);
    color: var(--cp-muted);
}

.cp-strip b { color: var(--cp-ink); }

/* --- Stat tiles --------------------------------------------------------- */
/* A row of headline numbers - tips today, strike rate, P/L. Each tile is a
   big figure over a small label. A tile can be a <button> (a filter that
   toggles) and takes .is-active when it is on. */

.cp-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--cp-space-3);
    list-style: none;
    margin: 0;
    padding: 0;
}

.cp .cp-tile {
    display: block;
    width: 100%;
    background: var(--cp-surface);
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius);
    padding: var(--cp-space-3) var(--cp-space-4);
    color: var(--cp-muted);
    font: inherit;
    font-size: var(--cp-text-sm);
    text-align: left;
    text-decoration: none;   /* a tile may be a link */
    line-height: 1.35;
}

.cp .cp-tile b {
    display: block;
    color: var(--cp-ink);
    font-size: var(--cp-text-h2);
    font-weight: 800;
    letter-spacing: var(--cp-track-h2);
    line-height: 1.05;
    margin-bottom: 2px;
}

.cp .cp-tile small {
    display: block;
    font-size: var(--cp-text-xs);
    color: var(--cp-muted);
}

.cp button.cp-tile { cursor: pointer; }
.cp button.cp-tile:hover { border-color: var(--cp-accent-line); }
.cp .cp-tile.is-active {
    background: var(--cp-accent-dim);
    border-color: var(--cp-accent-line);
    color: var(--cp-accent-ink);
}
.cp .cp-tile.is-active b { color: var(--cp-accent-ink); }

/* --- Form controls ------------------------------------------------------ */
/* Text, date and select controls on the same metrics as .cp-btn--sm, so a
   control and a button sit level in a toolbar. color-scheme follows the
   theme, which is what makes the native date picker readable in light. */

.cp .cp-input {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
    padding: 6px 12px;
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius);
    background: var(--cp-surface);
    color: var(--cp-ink);
    font: inherit;
    font-size: var(--cp-text-sm);
    color-scheme: inherit;
}

.cp .cp-input:focus-visible {
    outline: 2px solid var(--cp-focus);
    outline-offset: 2px;
    border-color: var(--cp-accent-line);
}

.cp-toolbar {
    display: flex;
    align-items: center;
    gap: var(--cp-space-2);
    flex-wrap: wrap;
}

/* --- Signal / result banner --------------------------------------------- */

.cp-signal {
    background: var(--cp-accent-dim);
    border: 1px solid var(--cp-accent-line);
    border-radius: var(--cp-radius);
    padding: 14px 16px;
    font-size: var(--cp-text-sm);
}

.cp-signal strong { color: var(--cp-accent-ink); }

/* --- Grid --------------------------------------------------------------- */

.cp-grid {
    display: grid;
    grid-template-columns: repeat(var(--cp-cols, 3), minmax(0, 1fr));
    gap: 18px;
}

@media (max-width: 950px) {
    .cp-grid { grid-template-columns: 1fr; }
    .cp-toc  { position: static; display: flex; gap: var(--cp-space-4); flex-wrap: wrap; border-left: 0; padding-left: 0; }
}

/* ==========================================================================
   Bootstrap bridge
   ==========================================================================

   The reuse win. Bootstrap 5.3 reads its own CSS variables, so pointing those
   at our tokens rethemes every existing .card, .btn, .table and .nav across
   400-odd files without touching their markup or writing replacements.

   Scoped under .cp so it only applies to converted pages.
   ========================================================================== */

.cp {
    --bs-body-bg:           var(--cp-bg);
    --bs-body-color:        var(--cp-ink);
    --bs-body-font-family:  var(--cp-font);
    --bs-emphasis-color:    var(--cp-ink);
    --bs-secondary-color:   var(--cp-muted);
    --bs-border-color:      var(--cp-line);
    --bs-border-radius:     var(--cp-radius);
    --bs-link-color:        var(--cp-accent-ink);
    --bs-link-hover-color:  var(--cp-accent-ink);
    --bs-code-color:        var(--cp-accent-ink);
}

.cp .card {
    --bs-card-bg:           var(--cp-surface);
    --bs-card-border-color: var(--cp-line);
    --bs-card-color:        var(--cp-ink);
    --bs-card-border-radius: var(--cp-radius-lg);
}

.cp .table {
    --bs-table-bg:          transparent;
    --bs-table-color:       var(--cp-muted);
    --bs-table-border-color: var(--cp-line);
    --bs-table-striped-bg:  var(--cp-surface-2);
    --bs-table-hover-bg:    var(--cp-surface);
}

/* Theme-blind utilities.
   Bootstrap's colour utilities hardcode a literal colour, which is meaningless
   once there are two themes. The site has 106 uses of .text-white, 58 of
   .bg-dark and 34 of .bg-light, nearly all of them written when dark was the
   only theme.

   .bg-dark and .bg-light are redirected to theme surfaces, so "dark panel"
   becomes "panel" and follows the theme. .text-white then has to follow, or a
   pairing of the two would be white-on-white in light mode. In dark mode none
   of this changes anything visible: --cp-ink is already near-white and the
   surfaces are already dark.

   !important is required to beat Bootstrap's own !important on these
   utilities. It is the only place in the system that uses it.

   .text-dark and .bg-white are deliberately NOT remapped: that pairing is
   self-consistent and readable in either theme, and 93 uses of .text-dark
   have not been audited. They stay on the Phase 3 checklist instead. */

/* Target the BACKGROUND utilities, not --bs-dark-rgb. Bootstrap builds both
   .bg-dark and .text-dark from that one variable, so remapping it turned
   .text-dark white in light mode - white on white wherever it sat on
   .bg-white. Overriding the two background utilities leaves .text-dark and
   .text-light on Bootstrap's own literals, which is what we want: paired with
   .bg-white they stay readable in either theme.

   The rgba() form is kept so .bg-opacity-* modifiers still work. */

.cp .bg-dark  { background-color: rgba(var(--cp-surface-rgb),   var(--bs-bg-opacity, 1)) !important; }
.cp .bg-light { background-color: rgba(var(--cp-surface-2-rgb), var(--bs-bg-opacity, 1)) !important; }

.cp .text-white { color: var(--cp-ink) !important; }

/* .bg-light is a theme surface now - near-black in dark mode - so Bootstrap's
   usual `bg-light text-dark` pairing would be dark on dark. Text on a bridged
   surface takes the ink, which is right in both themes. Found on the racing
   results panel. */
.cp .bg-light.text-dark,
.cp .bg-light .text-dark { color: var(--cp-ink) !important; }

/* Saturated fills need their text colour stated, because on the old site it
   came for free from the white body colour and under a light theme the body
   is dark ink. Which colour is measured, not assumed: the site overrides
   Bootstrap's bg-success with its own --accent-green (#7cb342), a light green
   on which white scores 2.5:1 and dark ink 6.7:1 - the live site has been
   failing AA there all along. Purple, primary, danger and secondary are dark
   enough that white wins.

   colour-ok: text on a brand fill is fixed in either theme. */
.cp .bg-danger, .cp .bg-primary, .cp .bg-secondary, .cp .bg-purple { color: #fff; }
.cp .bg-success, .cp .bg-orange                                   { color: #152111; }

.cp .bg-danger .text-muted, .cp .bg-primary .text-muted,
.cp .bg-secondary .text-muted, .cp .bg-purple .text-muted { color: rgba(255, 255, 255, .8) !important; }
.cp .bg-success .text-muted, .cp .bg-orange .text-muted   { color: rgba(21, 33, 17, .75) !important; }

.cp .btn-primary {
    --bs-btn-bg:            var(--cp-accent);
    --bs-btn-border-color:  var(--cp-accent);
    --bs-btn-color:         var(--cp-on-accent);
    --bs-btn-hover-bg:      var(--cp-accent);
    --bs-btn-hover-border-color: var(--cp-accent-line);
    --bs-btn-hover-color:   var(--cp-on-accent);
}

/* A link dressed as a button. `.cp a` in cp-base.css is (0,1,1) and paints
   every anchor accent-ink; Bootstrap's `.btn { color: var(--bs-btn-color) }`
   is only (0,1,0), so an <a class="btn btn-primary"> came out lime on lime -
   an invisible label - and every outline variant lost its own colour. Hand
   the colour back to Bootstrap's variables at (0,2,1), one state each, and
   every .btn-* variant is right again without naming any of them. */
.cp a.btn               { color: var(--bs-btn-color); }
.cp a.btn:hover,
.cp a.btn:focus-visible { color: var(--bs-btn-hover-color); }
.cp a.btn:active,
.cp a.btn.active        { color: var(--bs-btn-active-color); }
.cp a.btn.disabled      { color: var(--bs-btn-disabled-color); }

/* ==========================================================================
   Header and navigation
   ==========================================================================
   Used by includes/cp-header.php. Eight classes.

   Dropdowns are <details>/<summary>, so cp-base.css's own details/summary
   rules have to be overridden here - hence the .cp-drop scoping on each.

   Anything that can be an <a> sets its colour at (0,2,0) or higher. See rule 7
   in docs/design-system.md: `.cp a` at (0,1,1) otherwise wins and repaints the
   label with the link colour.
   ========================================================================== */

.cp-header {
    border-bottom: 1px solid var(--cp-line);
    background: var(--cp-bg);
    position: sticky;
    top: 0;
    z-index: 1030;
}

.cp-nav {
    min-height: 76px;
    display: flex;
    align-items: center;
    gap: var(--cp-space-5);
    padding-block: var(--cp-space-3);
}

/* --- Brand -------------------------------------------------------------- */

.cp .cp-brand {
    display: inline-flex;
    align-items: center;
    min-height: 48px;
    padding-left: 63px;
    background: var(--cp-logo) left center / 48px 48px no-repeat;
    font-size: 32px;
    font-weight: 800;
    letter-spacing: -1px;
    color: var(--cp-ink);
    text-decoration: none;
    margin-right: auto;
    white-space: nowrap;
}

.cp-brand em { font-style: normal; color: var(--cp-accent-ink); }

.cp-nav__links {
    display: flex;
    align-items: center;
    gap: var(--cp-space-5);
}

.cp-nav__end {
    display: flex;
    align-items: center;
    gap: var(--cp-space-2);
}

/* --- Dropdowns ---------------------------------------------------------- */

.cp .cp-drop {
    position: relative;
    border-bottom: 0;   /* undo cp-base.css */
    padding: 0;
}

.cp .cp-drop > summary {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 0;
    font-size: var(--cp-text-sm);
    font-weight: 500;
    color: var(--cp-muted);
    cursor: pointer;
    list-style: none;
    white-space: nowrap;
}

.cp .cp-drop > summary::-webkit-details-marker { display: none; }

.cp .cp-drop > summary::after {
    content: "";
    width: 7px;
    height: 7px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
}

.cp .cp-drop[open] > summary,
.cp .cp-drop > summary:hover,
.cp .cp-drop > summary[aria-current="true"] { color: var(--cp-accent-ink); }

.cp .cp-drop[open] > summary::after { transform: translateY(1px) rotate(225deg); }

.cp-menu {
    position: absolute;
    top: calc(100% + 10px);
    left: -14px;
    min-width: 232px;
    padding: var(--cp-space-2);
    background: var(--cp-surface);
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius);
    box-shadow: var(--cp-shadow);
    z-index: 20;
}

/* The panel sits 10px below the summary. Without this the pointer crosses a
   dead gap on its way down and the menu closes under it. An invisible strip
   over the gap keeps the pointer inside .cp-drop the whole way. */
.cp-menu::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: -10px;
    height: 10px;
}

.cp .cp-menu a {
    display: block;
    padding: 9px 12px;
    border-radius: var(--cp-radius-sm);
    font-size: var(--cp-text-sm);
    color: var(--cp-ink);
    text-decoration: none;
}

.cp .cp-menu a:hover { background: var(--cp-surface-2); color: var(--cp-accent-ink); }

/* --- Mobile ------------------------------------------------------------- */

.cp-nav__toggle {
    display: none;
    width: 42px;
    height: 42px;
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius);
    background: var(--cp-surface);
    cursor: pointer;
    padding: 0;
    place-items: center;
}

/* Three bars drawn from one element: the middle is the box, the outer two are
   shadows. Saves two spans of markup in every header. */
.cp-nav__toggle span {
    width: 17px;
    height: 1.5px;
    background: var(--cp-ink);
    box-shadow: 0 -5px 0 var(--cp-ink), 0 5px 0 var(--cp-ink);
}

@media (max-width: 900px) {
    .cp-nav { flex-wrap: wrap; gap: var(--cp-space-3); }
    .cp-nav__toggle { display: grid; order: 2; }
    .cp-nav__end { order: 3; margin-left: auto; }

    .cp-nav__links {
        order: 4;
        display: none;
        width: 100%;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        border-top: 1px solid var(--cp-line);
        padding-top: var(--cp-space-2);
    }

    .cp-nav__links[data-open] { display: flex; }

    .cp .cp-drop > summary { padding: 12px 0; font-size: var(--cp-text-base); }

    /* Inline, not floating: a positioned panel inside a narrow column has
       nowhere to go. */
    .cp-menu {
        position: static;
        min-width: 0;
        box-shadow: none;
        margin: 0 0 var(--cp-space-2);
        background: var(--cp-surface-2);
    }
}

/* At 32px the wordmark takes about two thirds of a 375px screen. The header
   still wraps to two rows on a phone, which is fine, but the brand should not
   dominate them both. */
@media (max-width: 600px) {
    .cp .cp-brand {
        min-height: 38px;
        padding-left: 48px;
        background-size: 38px 38px;
        font-size: 26px;
    }
}

/* --- Section subnav and footer ------------------------------------------ */
/* The strip under the site header that names a section and lists its pages,
   and the one-line footer that closes it. These are the Touchline landing
   pages' .tl-subnav / .tl-foot, generalised, for pages that carry the site
   header but not the legacy footer (the members area first). The Touchline
   pages keep their own copies in touchline-site.css. */

.cp-subnav {
    border-bottom: 1px solid var(--cp-line);
    background: var(--cp-surface);
}

.cp-subnav .cp-wrap {
    min-height: 52px;
    display: flex;
    align-items: center;
    gap: var(--cp-space-5);
    flex-wrap: wrap;
}

.cp-subnav__title {
    font-size: var(--cp-text-xs);
    letter-spacing: 0.15em;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--cp-muted);
    margin-right: auto;
}

.cp .cp-subnav a:not(.cp-btn) {
    font-size: var(--cp-text-sm);
    color: var(--cp-muted);
    text-decoration: none;
}

.cp .cp-subnav a:not(.cp-btn):hover,
.cp .cp-subnav a[aria-current="page"] { color: var(--cp-accent-ink); }

.cp-foot {
    border-top: 1px solid var(--cp-line);
    padding: 28px 0;
    color: var(--cp-muted);
    font-size: var(--cp-text-sm);
}

.cp-foot .cp-wrap {
    display: flex;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
}

.cp-foot__links { display: flex; gap: 24px; align-items: center; flex-wrap: wrap; }

.cp .cp-foot a { font-size: var(--cp-text-sm); color: var(--cp-muted); text-decoration: none; }
.cp .cp-foot a:hover { color: var(--cp-accent-ink); }

@media (max-width: 600px) {
    .cp-subnav .cp-wrap { gap: var(--cp-space-3); }
}

/* ==========================================================================
   Legacy component bridge
   ==========================================================================
   Overrides for components that live in punts.css and football.css rather than
   in a page's own <style> block.

   These are NOT edited at source. Those two files are shared by pages that
   have not opted in, and the pages actually load punts.min.css and
   football.min.css - so a source edit would need the minified copies
   regenerating and would put unconverted pages at risk for no gain.

   Overriding here instead is safe on both counts: every rule is scoped under
   .cp, which raises it to (0,2,0) against the legacy (0,1,0), and
   cp-components.css is loaded after both legacy files.

   Anything added here should eventually move into the component itself, when
   that section of the site is properly converted.
   ========================================================================== */

/* The legacy text variables. --text-dim is declared once, in odds-modal.css
   (#ced5e2), and read by cleverpunts.css, football.css, punts.css and a
   handful of inline styles in the panel includes; --text is read just as
   widely and declared nowhere. Neither ever followed a theme. Under .cp they
   are the ink tokens, which fixes every consumer at once. */
.cp {
    --text:     var(--cp-ink);
    --text-dim: var(--cp-muted);
}

/* Stayed dark in light mode: background came from punts.css's own
   --rp-surface, which does not follow the theme. */
.cp .rp-panel {
    background: var(--cp-surface);
    border-color: var(--cp-line);
}

/* Same problem, plus the reason panels looked almost white: the original is a
   2.5% white tint, which reads as a panel on a dark ground and as nothing at
   all on a light one. A real surface colour is needed, not a tint. */
.cp .ld-panel {
    background: var(--cp-surface);
    border-color: var(--cp-line);
}

.cp .ld-panel-hdr { border-bottom-color: var(--cp-line); }

/* The section hero without a photograph follows the theme. The football
   variant (.fp-hero-football, on the same element) is the photographic one
   and is defined next; at equal specificity it wins by coming later. */
.cp .fp-hero {
    background: linear-gradient(to right,
        var(--cp-hero-from) 0%,
        var(--cp-hero-mid) 35%,
        rgba(var(--cp-hero-rgb), .25) 60%,
        rgba(var(--cp-hero-rgb), 0) 100%);
}

/* The heroes with artwork. A scrim over a picture, and the picture is a
   token: the character in dark, a black-and-white ball in light, because the
   character was drawn for a dark ground and washes out on a pale one. The
   scrim fades to nothing at the right edge so the artwork is never dimmed,
   and --cp-hero-from is painted beneath it as the hero's own ground - the
   shorthand would otherwise leave that transparent. */
.cp .ld-hero,
.cp .fp-hero-football {
    background:
        linear-gradient(to right,
            var(--cp-hero-from) 0,
            var(--cp-hero-mid) 38%,
            rgba(var(--cp-hero-rgb), .82) 58%,
            rgba(var(--cp-hero-rgb), 0) 100%),
        var(--cp-hero-art) var(--cp-hero-art-pos) / var(--cp-hero-art-size) no-repeat
        var(--cp-hero-from);
}

/* Cyan on a light scrim is far too weak. */
.cp .ld-hero-eyebrow { color: var(--cp-accent-ink); }

/* The highlighted word in the hero title shimmers between two greens that
   were picked for a dark ground. The ends become the accent ink and the
   glint token is the highlight, so on light the shimmer collapses to a
   single readable green. The animation itself is left alone. */
.cp .fp-hero-h1 em {
    background-image: linear-gradient(90deg,
        var(--cp-accent-ink) 0,
        var(--cp-accent-glint) 50%,
        var(--cp-accent-ink) 100%);
}

/* --- football.css: the football landing page ---------------------------- */
/* football.css is written entirely for a dark ground: 46 declarations used by
   /football/ alone are either a translucent white or a near-black literal. The
   translucent whites keep their original alpha here and only swap the base
   colour, so the visual weight is unchanged in dark and they become a faint
   dark tint - visible - in light.
   
   Logo and photo plates are deliberately NOT included. Rules like
   .fp-team-logo use a white background as a pad behind a club crest, which is
   doing a job in both themes.
   
   This is interim. The real fix is converting football.css itself, which would
   cover every football page at once - see the note at the end of section 10. */

.cp .fp-league-chip,
.cp .fp-status-ft      { background: rgba(var(--cp-ink-rgb), .07); border-color: var(--cp-line); }
.cp .fp-scorer-tab     { background: rgba(var(--cp-ink-rgb), .06); border-color: var(--cp-line); }
.cp .fp-stats-tab      { background: rgba(var(--cp-ink-rgb), .07); }
.cp .fp-odds-btn,
.cp .fp-cup-chip       { background: rgba(var(--cp-ink-rgb), .05); border-color: var(--cp-line); }

/* The chip's hover tooltip is a title attribute drawn as ::after. Its
   background is --rp-s2, a dark literal from punts.css, and its text is
   --text, which nothing defines, so in light it was dark on dark. */
.cp .fp-league-chip[title]:hover::after {
    background: var(--cp-surface);
    border-color: var(--cp-line);
    color: var(--cp-ink);
    box-shadow: var(--cp-shadow);
}

.cp .fp-yt-input,
.cp .fp-yt-dropdown,
.cp .fp-yt-change-btn        { border-color: var(--cp-line); }
.cp .fp-yt-change-btn:hover  { border-color: var(--cp-accent-line); }

.cp .fp-ticker-item    { color: var(--cp-muted); }
/* Score and live minute are --fp-green (#22c55e) text: 2.3:1 on the light
   ground. accent-ink is the same lime in dark and a readable green in light. */
.cp .fp-ticker-score,
.cp .fp-ticker-live-badge { color: var(--cp-accent-ink); }

.cp .fp-rr-league-hdr  { background: rgba(var(--cp-ink-rgb), .03); border-top-color: var(--cp-line); border-bottom-color: var(--cp-line); }
.cp .fp-rr-card        { border-bottom-color: var(--cp-line); }
.cp .fp-rr-card:hover  { background: rgba(var(--cp-ink-rgb), .05); }
.cp .fp-rr-status-badge,
.cp .fp-rr-poss-bar    { background: rgba(var(--cp-ink-rgb), .08); }

/* Two decorative near-black gradients. They become surface gradients, which
   loses their faint green cast but keeps them on the palette in both themes. */
.cp .fp-motd,
.cp .fp-stat-card {
    background: linear-gradient(135deg, var(--cp-surface), var(--cp-surface-2));
}

/* --- cleverpunts.css + football.css: second pass ------------------------ */
/* My first scan of this page missed these two ways: it did not look in
   cleverpunts.css at all, and it only matched hex plus rgba(255,255,255,..),
   so dark rgba() literals slipped through. Corrected, the page had 17 genuine
   problems rather than the 20 originally bridged. */

/* Background came from --fp-card, which chains through cleverpunts.css to
   punts.css's --rp-s2 and never follows the theme. Same root cause as
   .rp-panel. */
.cp .fp-fixture-card       { background: var(--cp-surface); border-color: var(--cp-line); }
.cp .fp-fixture-card:hover { border-color: var(--cp-accent-line); }

/* Hairline rules drawn as a few percent of white: invisible on a light ground. */
.cp .fp-fixture-odds,
.cp .fp-yt-opponent-section,
.cp .fp-yt-fixture-footer,
.cp .fp-rr-body-inner                    { border-top-color: var(--cp-line); }
.cp .fp-fixture-meta                     { border-top-color: var(--cp-line); }
.cp .fp-team-stat-row,
.cp .fp-injury-row                       { border-bottom-color: var(--cp-line); }
.cp .fp-table-panel .rp-panel-hdr select { border-color: var(--cp-line); }

.cp .mobile-nav-link:hover,
.cp .mobile-nav-link.active { background: rgba(var(--cp-ink-rgb), .1); }

/* --- football.css: light text literals ---------------------------------- */
/* Third category my scan kept missing. It filtered hex by darkness, so a
   solid color:#fff was never flagged - which is exactly the thing that fails
   on a light ground. These are all "the brightest text": scores, stat values,
   emphasised ticker text.
   
   Deliberately NOT included: .nav-item-sidebar:hover and .date-card.active
   are white text on an orange and a blue fill respectively, which is correct
   in either theme. A light literal is only wrong when it sits on the page
   ground. */

.cp .fp-ticker-item strong,
.cp .fp-ticker-item:hover,
.cp .fp-live-score,
.cp .fp-motd-score,
.cp .fp-motd-preview-link:hover,
.cp .fp-fixture-score,
.cp .fp-yt-scoreline,
.cp .fp-stat-value,
.cp .fp-cup-chip:hover { color: var(--cp-ink); }

/* An injury doubt is a status, and #fbbf24 scores about 1.7:1 on the light
   ground. --cp-warn is a darker amber in light for exactly this. */
.cp .fp-yt-inj-group.doubtful { color: var(--cp-warn); }

/* --- cleverpunts.css: the home page's top cards ------------------------- */
/* Six quick-link cards, each a character drawn over a fixed dark gradient
   (#070d16 to #0f2727) with a 16px radius and a green-tinted border. The
   bridge flips their ink to --cp-ink, so in light the text was dark on a
   dark card. The gradient now runs between the two surface tokens, which
   keeps the dark look and turns pale in light; the character stays. The
   radius and border match .fp-featured-box, so the strip reads as one set
   of panels with the rest of the page.

   background-image has to be restated per variant because the character and
   the gradient are the same declaration in the legacy sheet. */
.cp #top-cards .stats-card {
    border-radius: var(--cp-radius);
    border-color: var(--cp-line);
    color: var(--cp-ink);
}

.cp #top-cards .card-title-custom { color: var(--cp-ink); }

.cp #top-cards .stats-card.cheeky   { background-image: url(/images/cleverman-wink.webp),     linear-gradient(180deg, var(--cp-surface) 0, var(--cp-surface-2) 100%); }
.cp #top-cards .stats-card.clever   { background-image: url(/images/cleverman_colour2.webp),  linear-gradient(180deg, var(--cp-surface) 0, var(--cp-surface-2) 100%); }
.cp #top-cards .stats-card.stupid   { background-image: url(/images/cleverman_colour3.webp),  linear-gradient(180deg, var(--cp-surface) 0, var(--cp-surface-2) 100%); }
.cp #top-cards .stats-card.hopeless { background-image: url(/images/cleverman-hopeless.webp), linear-gradient(180deg, var(--cp-surface) 0, var(--cp-surface-2) 100%); }
.cp #top-cards .stats-card.horse    { background-image: url(/images/cleverman-horse.webp),    linear-gradient(180deg, var(--cp-surface) 0, var(--cp-surface-2) 100%); }
.cp #top-cards .stats-card.football { background-image: url(/images/cleverman-football.webp), linear-gradient(180deg, var(--cp-surface) 0, var(--cp-surface-2) 100%); }

/* --- punts.css: the --rp-* navy palette and the Richest Races widget ----- */
/* punts.css builds the Richest Races widget (and the rp-* panels) on its own
   :root palette - four navy surfaces, a blue-grey muted, amber gold, silver,
   bronze and a race-time green - plus odds-modal.css's --border-dim. None of
   it follows the theme; .rr-row:hover painting --rp-s2 (#1e293b) under dark
   ink is the visible failure in light.

   The palette is re-pointed at the tokens under .cp, which fixes every
   consumer of those variables at once: surfaces to surfaces, gold to warn,
   the greens to ok, the hairline to line. Silver and bronze have no token
   and are too pale for a light ground, so they get darker literals there. */
.cp {
    --rp-surface: var(--cp-surface);
    --rp-s2:      var(--cp-surface-2);
    --rp-s3:      var(--cp-line);
    --rp-muted:   var(--cp-muted);
    --rp-gold:    var(--cp-warn);
    --rr-green:   var(--cp-ok);
    --rr-silver:  #9ca3af;
    --rr-bronze:  #cd7c4a;
    --border-dim: var(--cp-line);
}

[data-theme="light"] .cp {
    --rr-silver:  #5b6470;
    --rr-bronze:  #8a4b22;
}

.cp .rr-card { border-radius: var(--cp-radius); }

/* A navy-to-navy gradient literal. */
.cp .rr-header { background: var(--cp-surface-2); }

/* Gold text with a pale-yellow glint: fine in dark, vanishes on white. The
   glint token collapses the shimmer to a solid in light. */
.cp .rr-header-title:hover { color: var(--cp-warn-glint); }
.cp .rr-prize-featured {
    background-image: linear-gradient(90deg,
        var(--cp-warn) 0%, var(--cp-warn-glint) 45%, var(--cp-warn) 100%);
}
.cp .rr-prize-pill { color: var(--cp-warn); }

/* Hover and pill fills as an ink tint, so they read as a lift in either
   theme rather than a dark slab. */
.cp .rr-row:hover  { background: rgba(var(--cp-ink-rgb), .05); }
.cp .rr-meta-pill  { background: rgba(var(--cp-ink-rgb), .08); }

/* A literal sky blue for the course-ranked badge: 2.6:1 on the light ground. */
.cp .rr-rank-course {
    color: var(--cp-accent-ink);
    border-color: var(--cp-accent-line);
    background: var(--cp-accent-dim);
}

/* ==========================================================================
   Page inline styles: judgement calls
   ==========================================================================
   The mechanical restatements for the pages converted in one pass live in
   the generated cp-page-bridge.css. What that scan could not decide is here:
   status colours used as text, the legacy colour variables, heroes and a
   few dark islands. Organised by page.
   ========================================================================== */

/* --- Legacy colour variables ------------------------------------------- */
/* The pages read var(--green, #4ade80), var(--cyan, #22d3ee), var(--gold,
   ...) and var(--red, ...) - mostly undefined, so the pastel fallback wins,
   and every one of those fallbacks was chosen for a dark ground. Aliased to
   the tokens, they read in both themes. The odds modal, which owns --gold,
   restates it. */
.cp {
    --green: var(--cp-ok);
    --cyan:  var(--cp-info);
    --gold:  var(--cp-warn);
    --red:   var(--cp-bad);
}

/* --- football/gamePreview.php ------------------------------------------ */
/* --fp-green (#22c55e) as text: 2.3:1 on the light ground. Fills that use it
   are left alone. */
.cp .fmp-team-pos,
.cp .fmp-countdown,
.cp .fmp-card-hdr-icon,
.cp .fmp-tab.active,
.cp .fmp-tab:hover,
.cp .fmp-signal-val.over,
.cp .fmp-conf-high,
.cp .fmp-odds-btn2-price,
.cp .fmp-ht-wdl .w,
.cp .fmp-delta.pos,
.cp .fmp-ai-title,
.cp .fmp-ai-verdict-lbl,
.cp .fmp-keypoints li::before { color: var(--cp-ok); }

.cp .fmp-signal-val.under,
.cp .fmp-h2h-res.aw,
.cp .fmp-inj-doubt            { color: var(--cp-warn); }
.cp .fmp-conf-medium,
.cp .fmp-h2h-res.hw           { color: var(--cp-info); }
.cp .fmp-ht-wdl .l,
.cp .fmp-delta.neg,
.cp .fmp-inj-out              { color: var(--cp-bad); }

/* The hero is a dark green-to-green gradient; on the hero tokens instead. */
.cp .fmp-hero {
    background: linear-gradient(135deg, var(--cp-hero-from), var(--cp-hero-mid));
    border-color: var(--cp-line);
}

/* --- football/teams/index.php ------------------------------------------ */
.cp .tp-res.W,
.cp .tp-rating.hi,
.cp .ld-mini-pos.pos-el          { color: var(--cp-ok); }
.cp .tp-res.L,
.cp .tp-badge-inj,
.cp .ld-mini-pos.pos-relegation  { color: var(--cp-bad); }
.cp .tp-badge-c,
.cp .tp-rating.mid,
.cp .ld-mini-pos.pos-playoff,
.cp .ld-mini-pos.pos-rel-playoff { color: var(--cp-warn); }
.cp .ld-mini-pos.pos-promotion   { color: var(--cp-info); }
.cp .ld-mini-pos.pos-uecl        { color: var(--cp-violet); }

/* --- football/match-stats/liveStats.php -------------------------------- */
.cp .ls-event-minute { background: var(--cp-surface-2); }

/* --- horseracing/courses/index.php ------------------------------------- */
/* Same scrim-over-photograph treatment as the football heroes. */
.cp .cv-hero {
    background:
        linear-gradient(to right,
            var(--cp-hero-from) 0,
            var(--cp-hero-mid) 38%,
            rgba(var(--cp-hero-rgb), .82) 60%,
            rgba(var(--cp-hero-rgb), 0) 100%),
        url(/images/racing-hero-bg.webp) right center / cover no-repeat
        var(--cp-hero-from);
}
.cp .cv-select option { background: var(--cp-surface); }
/* The course viewer is a dark canvas in both themes; its loading text is
   pinned to the dark theme's muted so it stays readable on it. */
.cp .cv-viewer-loading { color: #a9b8c4; }

/* --- punts/cheeky ------------------------------------------------------- */
.cp .dp-status-won,
.cp .dp-winner-leg-tick { color: var(--cp-ok); }
.cp .dp-status-lost     { color: var(--cp-bad); }
.cp .dp-winner-badge    { color: var(--cp-warn); }

/* --- horseracing/richest-races/index.php ------------------------------- */
.cp .rp-lb-btn.active { color: var(--cp-warn); }

/* --- predictions.css.php: Sid's tips ------------------------------------ */
/* Shared by /horseracing/tips/, full-tips.php and /horseracing/. It carries
   its own :root palette - a turf green, a gold, three dark greens for the
   ground and cards, a green-grey muted - and sets Playfair Display on every
   number and horse name. Under .cp the palette is the tokens and the type is
   the system font; the rules below cover what a variable swap cannot: the
   green fills with white text, the gold used as ink, and the literals.

   The tips page draws its own hero from the components when the theme is
   on; .site-header is bridged for the other two pages, which still render
   the legacy one. */
.cp {
    --turf:         var(--cp-accent-line);
    --turf-light:   var(--cp-accent-line);
    --turf-dark:    var(--cp-surface-2);
    --gold-light:   var(--cp-warn-glint);
    --track:        var(--cp-bg);
    --card-bg:      var(--cp-surface);
    --card-border:  var(--cp-line);
    --text-muted:   var(--cp-muted);
    --high-green:   var(--cp-ok);
    --medium-amber: var(--cp-warn);
    --low-slate:    var(--cp-muted);
    /* read by .latest-results-strip and its chips, defined nowhere */
    --border:       var(--cp-line);
    --bg:           var(--cp-bg);
}

.cp .site-header {
    background: linear-gradient(135deg, var(--cp-hero-from), var(--cp-hero-mid));
    border-bottom-color: var(--cp-line);
}
.cp .site-header::before { display: none; }

/* Playfair Display on figures and horse names: the system font instead. */
.cp .stat-pill .stat-num,
.cp .compact-time,
.cp .meeting-title,
.cp .race-time,
.cp .tip-horse {
    font-family: var(--cp-font);
    letter-spacing: var(--cp-track-h3);
}
.cp .tip-horse .ew-badge { font-family: var(--cp-font); }

/* Gold as ink becomes the accent ink; gold as a fill becomes the accent. */
.cp .stat-pill .stat-num,
.cp .compact-time,
.cp .meeting-title,
.cp .race-time { color: var(--cp-accent-ink); }
.cp .tip-horse .ew-badge { background: var(--cp-accent); color: var(--cp-on-accent); }

/* Turf fills with white text: the accent with its own ink. */
.cp .view-tab.active,
.cp .time-pill:hover,
.cp .time-pill.active {
    background: var(--cp-accent);
    border-color: var(--cp-accent);
    color: var(--cp-on-accent);
}
.cp .view-tab:hover { background: var(--cp-accent-dim); color: var(--cp-accent-ink); }
.cp .meeting-pill:hover,
.cp .meeting-pill.active { background: var(--cp-accent-dim); color: var(--cp-ink); }
.cp #filter-winners.active,
.cp #filter-tips.active {
    background: var(--cp-accent-dim);
    color: var(--cp-accent-ink);
    outline-color: var(--cp-accent-line);
}

/* Light text literals. */
.cp .race-course,
.cp .compact-tip,
.cp .tip-horse,
.cp .empty-title        { color: var(--cp-ink); }
.cp .compact-race-name,
.cp .key-points li,
.cp .prediction-text    { color: var(--cp-muted); }
.cp .key-points li      { border-bottom-color: var(--cp-line); }

/* The lost / danger red, #f08080, is a pastel for dark. */
.cp .badge-outcome-lost,
.cp .badge-outcome-pulled-up,
.cp .badge-outcome-refused,
.cp .danger-chip,
.cp .danger-icon        { color: var(--cp-bad); }
.cp .result-banner.lost { border-left-color: var(--cp-bad); }

/* Tints that were rgba() of the turf literal. */
.cp .race-card-header   { background: linear-gradient(90deg, var(--cp-accent-dim) 0%, transparent 100%); }
.cp .tip-section        { background: rgba(var(--cp-accent-rgb), .07); }
.cp .meeting-header     { background: linear-gradient(135deg, var(--cp-accent-dim) 0%, transparent 100%); }
.cp .dangers-section    { background: rgba(var(--cp-ink-rgb), .03); }
.cp .race-card,
.cp .compact-race       { border-radius: var(--cp-radius); }

/* The date picker was forced dark; follow the theme. */
.cp .date-input { color-scheme: inherit; }

/* The tips pages' own hero, drawn when the theme is on: page head on the
   left, the day's figures as tiles on the right. */
.sid-hero {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--cp-space-5);
    align-items: center;
}
.sid-hero > * { grid-column: span 12; }
@media (min-width: 992px) {
    .sid-hero__intro { grid-column: span 5; }
    .sid-hero__tiles { grid-column: span 7; }
}
.cp .sid-hero h1 em { font-style: normal; color: var(--cp-accent-ink); }
.sid-datenav { margin-top: var(--cp-space-4); }
.sid-hero__tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 600px) {
    .sid-hero__tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* A losing day's P/L. */
.cp .cp-tile.is-down b { color: var(--cp-bad); }

/* The view tabs, meeting nav and content column were designed against the
   old header: centred, full-bleed, offset. Left-aligned under the page
   head, full width. */
.cp .view-tabs,
.cp .meeting-nav { background: none; border: 0; padding: 0; margin-bottom: var(--cp-space-4); }
.cp .view-tabs .container,
.cp .meeting-nav .container { padding: 0; max-width: none; }
.cp .view-tabs .justify-content-center,
.cp .meeting-nav .justify-content-center { justify-content: flex-start !important; margin-top: 0 !important; }
.cp .view-tab { border-color: var(--cp-line); }
.cp .offset-xl-1 { margin-left: 0; }
.cp .col-xl-10 { width: 100%; }

/* --- punts.css: the cheeky punt page --------------------------------------- */
/* /punts/cheeky/ (and daily-punt.php) on the rp-* palette bridged above,
   plus its own hero and a layout that never had the room it needs: three
   punt cards in two thirds of a 1220px measure went 3-across only at xxl,
   and otherwise stacked. Under .cp the page takes the wide measure, the
   cards get the whole width, and the old sidebar becomes a row beneath
   them with the recent winners first. The column classes in the markup
   are Bootstrap's; these hooks override their widths at the same
   breakpoints. */

/* Hero: a navy gradient literal, a shimmer that vanishes on white, and
   Bootstrap's text-white-50 on the strapline. */
.cp .rp-hero {
    background: linear-gradient(155deg, var(--cp-hero-from) 0%, var(--cp-hero-mid) 50%, var(--cp-hero-from) 100%);
    border-color: var(--cp-line);
    border-radius: var(--cp-radius-lg);
}
.cp .rp-hero::after { background: radial-gradient(ellipse at 80% 50%, rgba(var(--cp-accent-rgb), .10) 0%, transparent 70%); }
.cp .rp-hero-h1 { font-family: var(--cp-font); letter-spacing: var(--cp-track-h2); }
.cp .rp-hero-h1 em {
    background-image: linear-gradient(90deg, var(--cp-accent-ink) 0%, var(--cp-accent-glint) 50%, var(--cp-accent-ink) 100%);
}
.cp .rp-hero-eyebrow,
.cp .dp-hero-eyebrow { color: var(--cp-accent-ink); }
.cp .dp-hero-eyebrow::before { background: var(--cp-accent-ink); }
.cp .dp-hero-wm { opacity: var(--cp-hero-wm-opacity); }
.cp .text-white-50 { color: var(--cp-muted) !important; }   /* Bootstrap asserts white */

/* Ticker label: gold fill with black text; the accent with its own ink. */
.cp .dp-ticker-label { background: var(--cp-accent); color: var(--cp-on-accent); }

/* Layout. */
.cp .dp-main,
.cp .dp-side { width: 100%; }
.cp .dp-cards > [class*="col-"] { width: 100%; }
@media (min-width: 768px)  { .cp .dp-cards > [class*="col-"] { width: 50%; } }
@media (min-width: 992px)  { .cp .dp-cards > [class*="col-"] { width: 33.3333%; } }

.cp .dp-side {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--cp-space-4);
    align-items: start;
}
.cp .dp-side > * { grid-column: span 12; margin: 0 !important; }
.cp .dp-side-winners { order: 1; }
.cp .dp-side-form    { order: 2; }
.cp .dp-side-ad      { order: 3; text-align: center; }
@media (min-width: 992px) {
    .cp .dp-side-winners,
    .cp .dp-side-form { grid-column: span 6; }
}

/* --- cleverpunts.css: .stats-card, .mini-card, the generic panels --------- */
/* The legacy site's all-purpose panel is .stats-card - background --bg-card
   (#2a2a32), 16px radius, no border - with .card-header-custom holding a
   .card-title-custom eyebrow whose colour is a literal #1a1a1f. .mini-card is
   its stat tile. The system builder is built entirely from them, as are the
   explain pages and race-stats. Under .cp they take the same treatment as
   .cp-panel and .cp-tile: surface, line, the system radius, the accent
   eyebrow.

   The home page's top cards are .stats-card too, under #top-cards; the id
   rules there outrank everything here, so they are unaffected. */
.cp .stats-card {
    background: var(--cp-surface);
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius-lg);
    padding: 22px;
    color: var(--cp-ink);
}

.cp .stats-card > .card-header-custom {
    margin: 0 0 var(--cp-space-4);
    padding-bottom: var(--cp-space-3);
    border-bottom: 1px solid var(--cp-line);
}

.cp .card-title-custom {
    color: var(--cp-accent-ink);
    font-size: var(--cp-text-xs);
    letter-spacing: .15em;
}

/* A page title inside a panel (the system builder's intro) sits at the
   page-head size, not the hero size cp-base gives a bare h1. */
.cp .stats-card h1 {
    font-size: clamp(26px, 3vw, 36px);
    letter-spacing: var(--cp-track-h2);
    margin: 0 0 var(--cp-space-3);
    max-width: none;
}

.cp .mini-card {
    background: var(--cp-surface-2);
    border: 1px solid var(--cp-line);
    border-radius: var(--cp-radius);
}
.cp .mini-card .card-label { color: var(--cp-muted); }

/* The legacy brand orange as an icon / text tint. !important because the
   legacy utility carries one. */
.cp .text-orange { color: var(--cp-accent-ink) !important; }

/* Bootstrap's forced-dark table and badge inside a themed panel. */
.cp .table-dark {
    --bs-table-bg:           var(--cp-surface-2);
    --bs-table-color:        var(--cp-ink);
    --bs-table-border-color: var(--cp-line);
    --bs-table-striped-bg:   var(--cp-surface);
    --bs-table-hover-bg:     var(--cp-surface);
    color: var(--cp-ink);
}
.cp .text-bg-dark {
    background-color: var(--cp-surface-2) !important;
    color: var(--cp-ink) !important;
}

/* --- football fixtures: the date scroller ------------------------------- */
/* Each date is a Bootstrap .card carrying .text-dark, with a light-grey
   hover and a blue active fill from cleverpunts.css. Between the card
   variable bridge, the .text-dark literal and the utility overrides the
   result in dark was pale text on a pale card. Stated outright, both
   states, both themes; !important because Bootstrap's text utilities
   carry one - and so does .bg-white, which every inactive date card
   wears, so the background needs it too or the card stays white under
   the ink. */
.cp .date-card {
    background: var(--cp-surface) !important;
    border: 1px solid var(--cp-line);
    color: var(--cp-ink) !important;
}
.cp .date-card .text-dark  { color: var(--cp-ink) !important; }
.cp .date-card .text-muted { color: var(--cp-muted) !important; }
.cp .date-card:hover { background: var(--cp-surface-2) !important; border-color: var(--cp-accent-line); }
/* The active card is the lime accent fill, which takes dark ink. The
   anchor's colour is not enough: Bootstrap's .card-body sets its own
   colour from --bs-card-color, which the card bridge above binds to
   --cp-ink - near-white in dark - so the day number and day name came
   out white on lime. Rebind the variable on the active card and state
   the body's colour outright. */
.cp .date-card.active {
    --bs-card-color: var(--cp-on-accent);
    background: var(--cp-accent) !important;
    border-color: var(--cp-accent);
    color: var(--cp-on-accent) !important;
}
.cp .date-card.active .card-body,
.cp .date-card.active .text-dark,
.cp .date-card.active .text-muted { color: var(--cp-on-accent) !important; }

/* --- horseracing: the enhanced racecard's runner card --------------------- */
/* Each runner is half the page (its race history takes the other half),
   the card body is three Bootstrap columns, and the third of those held
   four rating tiles in a nested .row of .col-3s. Under the legacy
   container-fluid that nesting had a whole monitor to spread across; at
   the 1220px measure each tile was left 22px wide and "CPR 109" stacked
   one character per line. The page now takes the wide measure, and the
   body reflows so it works at any width: the ratings - the numbers a
   punter scans for first - become a full-width strip at the top with the
   headgear / wind-op / last-ran flags beside them, and Connections and
   Breeding share the row beneath as two columns. The rc-* hooks are in
   php/horseracing/racecard-enhanced-content.php; nothing changes for the
   legacy page. */
.cp .rc-runner-body { row-gap: var(--cp-space-4); }
.cp .rc-runner-body > .rc-ratings {
    order: -1;
    flex: 0 0 100%;
    width: 100%;
    max-width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--cp-space-3) var(--cp-space-4);
}
.cp .rc-ratings > h6 { flex: 0 0 100%; margin: 0; }
.cp .rc-runner-body > .rc-connections,
.cp .rc-runner-body > .rc-breeding { flex: 0 0 50%; width: 50%; max-width: 50%; }
.cp .rc-runner-body p { font-size: var(--cp-text-sm); }

/* The tiles: Bootstrap's gutters are the width budget here, so the nested
   .row becomes a grid and each .col-3 sheds its padding. The tile itself
   takes the .cp-tile look. */
.cp .rc-rating-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--cp-space-2);
    margin: 0;
    flex: 1 1 280px;
}
.cp .rc-rating { flex: none; width: auto; max-width: none; padding: 0; margin-top: 0; }
.cp .rc-rating > .border {
    background: var(--cp-surface-2);
    border-color: var(--cp-line) !important;
    border-radius: var(--cp-radius) !important;
    padding: var(--cp-space-2) var(--cp-space-1) !important;
}
.cp .rc-rating small {
    font-size: var(--cp-text-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--cp-muted) !important;
}
.cp .rc-rating strong {
    display: block;
    font-size: var(--cp-text-lg);
    font-weight: 800;
    letter-spacing: var(--cp-track-h3);
    line-height: 1.15;
    color: var(--cp-ink);
}
.cp .rc-flags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cp-space-1);
    flex: 1 1 200px;
    margin-top: 0 !important;
}

@media (max-width: 575px) {
    .cp .rc-runner-body > .rc-connections,
    .cp .rc-runner-body > .rc-breeding { flex-basis: 100%; width: 100%; max-width: 100%; }
}
