/* GENERATED by scripts/build_marketing_css.py from app.css; do not edit.
 * The marketing pages load this instead of app.css. */
/* --------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------- */

:root {
    /* Field palette */
    --c-field-900: #07371f;      /* Midnight field — header, dark surfaces */
    --c-field-700: #0b6b3a;      /* Primary brand green — buttons, mark */
    --c-field-500: #2d8a4e;      /* Mid green — hover, accents */
    --c-field-300: #3fb56b;      /* Highlight green — focus rings, success */
    --c-field-50:  #ecf6f0;      /* Faint tint — surfaces / hover wash */

    /* Accents */
    --c-endzone:      #f5c116;   /* End-zone yellow — eyebrow, highlights */
    --c-endzone-deep: #d99f08;   /* End-zone hover */
    /* Copy that sits ON the end-zone yellow. White is unreadable there
       (1.7:1 — it fails AA by a mile), so anything filled with --c-endzone
       reverses to dark text: --c-ink-900 for the headline (10.4:1) and this
       for the secondary lines (7.2:1). */
    --c-endzone-ink:  #43350a;

    /* Neutrals */
    --c-chalk:     #fafaf7;      /* Off-white page background */
    --c-paper:     #ffffff;      /* Card / sheet background */
    --c-ink-900:   #0f1d17;      /* Primary text — dark green-black */
    --c-ink-600:   #4b5853;      /* Secondary text */
    --c-ink-400:   #65706b;      /* Muted text: 4.9:1 on chalk, 5.1:1 on paper (AA) */
    --c-line:      #e3e9e5;      /* Hairline borders */
    --c-line-soft: #eef2ef;      /* Even softer dividers */

    /* Status */
    --c-error-bg:  #fdecea;
    --c-error-line:#f5c6cb;
    --c-error-ink: #8a1218;

    /* Alert red — a SOLID call-to-action red, for the one action a coach has
       to find fastest on a sideline. Distinct from the --c-error-* trio above,
       which tints a failure message rather than filling a control.
       --c-danger-600 / --c-danger-50 were already referenced with these exact
       values as inline fallbacks (.editor-toolbar__btn--danger); naming them
       here settles the dangling reference without changing that button. */
    --c-danger-700: #8f1b13;     /* Hover / pressed — 9.0:1 on white text */
    --c-danger-600: #b42318;     /* Base fill — 6.6:1 on white text (AA) */
    --c-danger-100: #ffe4e1;     /* Tinted body copy ON the red — 5.5:1 */
    --c-danger-50:  #fef3f2;     /* Faint wash */

    /* Typography */
    --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --font-display: "Bebas Neue", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

    /* Type scale — display sizes scale fluidly between mobile and desktop. */
    --t-section:clamp(1.65rem, 2.4vw + 1rem, 2.5rem);
    --t-card:   1.125rem;
    --t-body:   1rem;
    --t-meta:   0.875rem;
    --t-eyebrow:0.78rem;

    /* Radii */
    --r-tile: 14px;
    --r-card: 12px;
    --r-pill: 999px;
    --r-input: 10px;

    /* Elevation — used sparingly to keep the surface editorial */
    --shadow-card: 0 1px 2px rgba(15, 29, 23, 0.04),
                   0 8px 24px -12px rgba(15, 29, 23, 0.18);
    --shadow-soft: 0 1px 2px rgba(15, 29, 23, 0.04);
}

/* --------------------------------------------------------------------
   2. Base + reset
   -------------------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    overflow-x: hidden;  /* horizontal scrolling is forbidden by Req 16.1 */
}

body {
    font-family: var(--font-sans);
    font-size: var(--t-body);
    line-height: 1.55;
    color: var(--c-ink-900);
    background: var(--c-chalk);
    padding-top: env(safe-area-inset-top, 0);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

img, svg {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: var(--c-field-700);
    text-decoration: none;
    transition: color 120ms ease;
}

a:hover, a:focus {
    color: var(--c-field-500);
    text-decoration: underline;
}

button { font: inherit; cursor: pointer; }

::selection {
    background: color-mix(in srgb, var(--c-endzone) 50%, transparent);
    color: var(--c-ink-900);
}

/* --------------------------------------------------------------------
   Accessibility (P2 pass)
   -------------------------------------------------------------------- */

/* A clear keyboard focus ring for every interactive element. ``:focus-visible``
   only shows for keyboard/AT users, so mouse clicks stay clean. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid var(--c-endzone-deep);
    outline-offset: 2px;
    border-radius: 4px;
}

/* A link inside running text needs more than colour to stand out (WCAG
   1.4.1). Class-less links in a paragraph are the inline ones; buttons,
   nav and card links all carry a class and keep their own styling. */
p a:not([class]) {
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* Smooth in-page anchor scrolling (e.g. the CTA's "See it in action"),
   but only when the user hasn't asked for reduced motion. */
@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}

/* Reduced-motion safety net for the marketing page: even if a transition
   or animation is added later without its own guard, it collapses to a
   near-instant change for users who ask for reduced motion. */
@media (prefers-reduced-motion: reduce) {
    .landing *,
    .landing *::before,
    .landing *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* --------------------------------------------------------------------
   3. App shell + header
   -------------------------------------------------------------------- */

.app-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    width: 100%;
    max-width: 100vw;
}

.app-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.85rem 1.1rem;
    background: var(--c-field-900);
    color: #ffffff;
    position: sticky;
    top: 0;
    z-index: 10;
    /* Yard-line accent — a single thin band of end-zone yellow that
       reads as a referee's sideline marker under the header. */
    border-bottom: 3px solid var(--c-endzone);
    transition: padding 0.2s ease, box-shadow 0.2s ease;
}
/* Condensed state once the page scrolls (toggled by the inline script in
   base.html) — tighter and lifted so the brand + CTA stay compact. The
   doubled class out-specifies the responsive ``.app-header`` padding rule
   so the vertical shrink wins at every breakpoint. */
.app-header.app-header--scrolled {
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
    box-shadow: 0 10px 26px -18px rgba(7, 24, 14, 0.75);
}
@media (prefers-reduced-motion: reduce) {
    .app-header { transition: none; }
}

.app-header__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    font-weight: 700;
    color: #ffffff;
    font-size: 1rem;
    letter-spacing: -0.005em;
}

.app-header__brand:hover,
.app-header__brand:focus {
    color: #ffffff;
    text-decoration: none;
}

.brand-mark {
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: 7px;
    display: block;
}

.brand-wordmark {
    display: inline-flex;
    /* Single-line wordmark — the "Flag Football" tagline was removed
       once tackle support was added to the roadmap (sport is per-user
       now). Center-align so the wordmark vertically meets the football
       mark next to it. */
    align-items: center;
    line-height: 1;
}

.brand-wordmark__name {
    font-weight: 800;
    font-size: 1.05rem;
    letter-spacing: -0.01em;
}

.app-header__nav {
    display: flex;
    gap: 0.5rem;
    margin-left: auto;
    min-height: 44px;
    align-items: center;
}

/* Mobile nav toggle (design item #7). Hidden controls on desktop; the
   hamburger + collapsible dropdown only engage below the breakpoint. */
.app-header__nav-toggle {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}
.app-header__hamburger {
    display: none;
    margin-left: auto;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--r-input);
    color: #ffffff;
    cursor: pointer;
}
.app-header__hamburger:hover,
.app-header__nav-toggle:focus-visible + .app-header__hamburger {
    background: rgba(255, 255, 255, 0.1);
}

@media (max-width: 1023px) {
    .app-header__hamburger { display: inline-flex; }
    .app-header__nav--collapsible {
        /* Drop the authenticated nav into a full-width panel under the
           header instead of letting 9 links overflow and clip. */
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        margin-left: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0.1rem;
        padding: 0.5rem 1rem 0.85rem;
        background: var(--c-field-900);
        border-bottom: 3px solid var(--c-endzone);
        box-shadow: 0 12px 24px -12px rgba(7, 24, 14, 0.6);
    }
    .app-header__nav-toggle:checked ~ .app-header__nav--collapsible {
        display: flex;
    }
    .app-header__nav--collapsible a,
    .app-header__nav--collapsible .app-header__logout {
        width: 100%;
        padding: 0.7rem 0.6rem;
    }
    .app-header__nav--collapsible .app-header__logout-btn {
        width: 100%;
    }
    .app-header__nav--collapsible .app-header__cta {
        text-align: center;
        margin-top: 0.25rem;
    }
}

.app-header__nav a {
    color: #ffffff;
    padding: 0.5rem 0.6rem;
    border-radius: var(--r-pill);
    font-size: 0.95rem;
    font-weight: 500;
}

.app-header__nav a:hover,
.app-header__nav a:focus {
    background: rgba(255, 255, 255, 0.08);
    text-decoration: none;
    color: #ffffff;
}

.app-header__cta {
    background: var(--c-endzone);
    color: var(--c-ink-900) !important;
    padding: 0.5rem 1rem !important;
    border-radius: var(--r-pill);
    line-height: 1;
    font-weight: 700;
}

.app-header__cta:hover,
.app-header__cta:focus {
    background: var(--c-endzone-deep);
    color: var(--c-ink-900) !important;
}

.app-header__logout {
    margin: 0;
    display: inline-flex;
    align-items: center;
}

.app-header__logout-btn {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.35);
    color: #ffffff;
    padding: 0.4rem 0.95rem;
    border-radius: var(--r-pill);
    font-size: 0.85rem;
    line-height: 1;
    font-weight: 500;
}

.app-header__logout-btn:hover,
.app-header__logout-btn:focus {
    border-color: #ffffff;
    background: rgba(255, 255, 255, 0.1);
}

/* Anonymous header fit (design item #7). The signed-out nav is three
   short inline links (Pricing / Sign in / Sign up) with no hamburger —
   it overflowed and clipped on phones. Rather than hide the Sign-up CTA
   behind a menu, tighten the inline nav so all three fit, and drop the
   wordmark text to the brand mark alone on the narrowest phones. Scoped
   with :not(--collapsible) so it never touches the authenticated dropdown
   (whose links need full tap padding). */
@media (max-width: 540px) {
    .app-header { gap: 0.5rem; }
    .app-header__nav:not(.app-header__nav--collapsible) { gap: 0.3rem; }
    .app-header__nav:not(.app-header__nav--collapsible) a {
        padding: 0.4rem 0.45rem;
        font-size: 0.85rem;
    }
    .app-header__nav:not(.app-header__nav--collapsible) .app-header__cta {
        padding: 0.4rem 0.7rem !important;
    }
}
/* Signed-out nav on phones. Its four links plus the one-line wordmark need
   ~426px, so between 361px and 440px the links broke mid-label ("Sign" /
   "in"). Labels never wrap; the wordmark sets on two lines instead, and the
   links' padding tightens. The signed-in nav collapses behind the hamburger
   and is left alone. */
.app-header__nav:not(.app-header__nav--collapsible) a { white-space: nowrap; }
@media (max-width: 440px) {
    .app-header { gap: 0.5rem; }
    .app-header__brand { gap: 0.45rem; }
    .brand-wordmark__name { display: block; max-width: 5.5em; font-size: 0.95rem; line-height: 1.1; word-spacing: 0.12em; }
    .app-header__nav:not(.app-header__nav--collapsible) { gap: 0.05rem; }
    .app-header__nav:not(.app-header__nav--collapsible) a { padding: 0.5rem 0.34rem; font-size: 0.88rem; }
    .app-header__nav:not(.app-header__nav--collapsible) .app-header__cta { padding: 0.5rem 0.75rem !important; }
}

@media (max-width: 380px) {
    .brand-wordmark { display: none; }   /* mark-only on the smallest phones (incl. 375px) */
}

.app-main {
    flex: 1 1 auto;
    width: 100%;
    padding: 1rem;
    max-width: 1120px;
    margin: 0 auto;
}

/* Opt-in modifier: pages that want the full viewport width (the
   playbook detail page's play grid + the editor's two-column field
   layout) set ``{% block main_modifiers %}app-main--wide{% endblock %}``
   in the template. Caps at the viewport with a small breathing-room
   padding instead of the global 1120px cap. */
.app-main--wide {
    max-width: none;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
}

@media (min-width: 1280px) {
    .app-main--wide {
        padding-left: 2rem;
        padding-right: 2rem;
    }
}

/* --------------------------------------------------------------------
   4. Button system (.btn)
   --------------------------------------------------------------------
   New shared primitives used by the landing surfaces. Existing
   ``.auth-button`` rules below are preserved for the other auth pages
   so we don't churn 10 templates in a single pass.
   ----------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    min-height: 48px;
    padding: 0.75rem 1.4rem;
    border-radius: var(--r-pill);
    border: 1.5px solid transparent;
    font-weight: 600;
    font-size: 1rem;
    line-height: 1;
    letter-spacing: -0.005em;
    text-decoration: none;
    transition: background 140ms ease, border-color 140ms ease,
                color 140ms ease, transform 80ms ease;
    cursor: pointer;
}

.btn:hover, .btn:focus { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn--primary {
    background: var(--c-field-700);
    color: #ffffff;
    border-color: var(--c-field-700);
}
.btn--primary:hover,
.btn--primary:focus {
    background: var(--c-field-500);
    border-color: var(--c-field-500);
    color: #ffffff;
}

.btn--ghost {
    background: transparent;
    color: var(--c-ink-900);
    border-color: var(--c-ink-900);
}
.btn--ghost:hover,
.btn--ghost:focus {
    background: var(--c-ink-900);
    color: #ffffff;
}

/* Solid end-zone yellow, dark letters (owner: red 2026-09-04, yellow
   2026-09-06). Used for "Get in-game advice" on both surfaces it appears on,
   so the sideline action looks the same wherever a coach meets it. Fill
   rather than outline, because a ghost button reads as secondary and this is
   the one control a coach hunts for mid-game.

   THE TEXT COLOUR IS NOT A STYLE CHOICE. White on this yellow is 1.7:1 —
   illegible in a gym, let alone in sunlight on a sideline — so the fill
   change forces dark text. Kept as --c-ink-900 (10.4:1) rather than pure
   black to match every other dark label on the page. */
.btn--alert {
    background: var(--c-endzone);
    color: var(--c-ink-900);
    border-color: var(--c-endzone);
}
.btn--alert:hover,
.btn--alert:focus {
    background: var(--c-endzone-deep);
    border-color: var(--c-endzone-deep);
    color: var(--c-ink-900);
}

.btn--large {
    min-height: 56px;
    padding: 0.95rem 1.85rem;
    font-size: 1.05rem;
}

.btn .btn__arrow {
    transition: transform 140ms ease;
}
.btn:hover .btn__arrow,
.btn:focus .btn__arrow { transform: translateX(3px); }

.btn .btn__icon {
    flex: 0 0 auto;
    margin-right: -0.05rem;
}

/* --------------------------------------------------------------------
   5. Landing hero
   -------------------------------------------------------------------- */

.landing { margin: 0; }

/* Landing only: the main column drops its 1120px cap and padding so colour
   bands run edge to edge. Every landing section caps its own text. */
.app-main.app-main--bleed {
    max-width: none;
    padding: 0;
}

/* TEMPORARY: beta-launch banner. Full-bleed strip above the hero in the
   brand's field-green / end-zone-yellow language. Remove this block (and the
   matching markup in templates/auth/landing.html) to retire the callout. */
.landing-beta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 0.7rem 1.25rem;
    background: var(--c-field-900);
    color: #ffffff;
    text-align: center;
    font-size: 0.95rem;
    line-height: 1.35;
}
.landing-beta__tag {
    flex: none;
    padding: 0.15rem 0.6rem;
    border-radius: 999px;
    background: var(--c-endzone);
    color: var(--c-ink-900);
    font-family: var(--font-display);
    font-size: 0.8rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}
.landing-beta__text a {
    color: var(--c-endzone);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.landing-beta__text a:hover {
    text-decoration: none;
}

/* "You're signed out" on the landing page: a full-width strip under the
   beta banner. The page's main column has no padding here, so the shared
   .pricing-notice box would sit flush against the left edge. */
.landing .landing-flash {
    max-width: none;
    margin: 0;
    padding: 0.7rem 1.25rem;
    border-width: 0 0 1px 0;
    border-radius: 0;
    text-align: center;
}

/* The hero is the field: night turf with mowing stripes, full bleed. The
   drawn play brings its own yard lines, so the band paints none. */
.landing-hero {
    position: relative;
    overflow: hidden;
    padding: 3rem 1.25rem 3.5rem;
    color: var(--c-chalk);
    background: repeating-linear-gradient(to bottom,
        var(--c-field-900) 0 80px, #093f25 80px 160px);
}

.landing-hero__inner {
    position: relative;
    display: grid;
    gap: 2.5rem;
    max-width: 1120px;
    margin: 0 auto;
    align-items: center;
}

.landing-hero__copy { max-width: 36rem; }

.landing-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    font-family: var(--font-display);
    font-size: var(--t-eyebrow);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--c-field-700);
    margin: 0 0 1.1rem 0;
    line-height: 1;
}
.landing-eyebrow::before {
    /* Small accent tab before the eyebrow text. ``currentColor`` ties
       it to the eyebrow's own color so the hero (Electric Blue) and the
       inverted steps section (Turf Green) both look intentional. */
    content: "";
    width: 28px;
    height: 3px;
    background: currentColor;
    display: inline-block;
    border-radius: 2px;
}

/* The page's <h1>. Bebas Neue is the scoreboard face; at hero size in
   chalk white it is the loudest thing on the page by design. */
.landing-hero__title {
    margin: 0 0 1.25rem 0;
    font-family: var(--font-display);
    font-weight: 400;          /* Bebas Neue ships single-weight */
    font-size: clamp(2.9rem, 4.4vw + 1rem, 5.1rem);
    line-height: 0.94;
    letter-spacing: 0.01em;
    text-transform: uppercase;
    color: #ffffff;
    text-wrap: balance;
}

.landing-hero__lede {
    margin: 0 0 1.75rem 0;
    max-width: 34rem;
    font-size: 1.125rem;
    line-height: 1.55;
    color: rgba(250, 250, 247, 0.84);
}

.landing-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
}
/* On turf the brand green button would disappear; the primary action takes
   the end-zone paint, the secondary is an outline in chalk. */
.landing-hero .btn--primary {
    background: var(--c-endzone);
    border-color: var(--c-endzone);
    color: var(--c-ink-900);
}
.landing-hero .btn--primary:hover,
.landing-hero .btn--primary:focus-visible {
    background: var(--c-endzone-deep);
    border-color: var(--c-endzone-deep);
    color: var(--c-ink-900);
}
.landing-hero .btn--ghost {
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.55);
}
.landing-hero .btn--ghost:hover,
.landing-hero .btn--ghost:focus-visible {
    background: rgba(255, 255, 255, 0.08);
    border-color: #ffffff;
    color: #ffffff;
}
.landing-hero .btn:focus-visible {
    outline: 3px solid #ffffff;
    outline-offset: 3px;
}

.landing-hero__formats {
    margin: 1.5rem 0 0 0;
    max-width: 34rem;
    font-size: 0.9rem;
    line-height: 1.5;
    color: rgba(250, 250, 247, 0.62);
}

/* The demo: the typed call, the play it becomes, and the calls to try. */
.landing-hero__demo {
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
    width: 100%;
    max-width: 30rem;
    margin: 0 auto;
}

.landing-hero__visual { position: relative; }

/* Scoped under .landing-hero__visual: the bare ``.play-card`` selector
   belongs to the print module further down this file. No card chrome —
   the drawing sits straight on the hero turf, its yard lines faded out at
   every edge so they dissolve into the band's own. */
.landing-hero__visual .play-card {
    position: relative;
    width: 100%;
    max-width: 22rem;
    margin: 0 auto;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
    color: #ffffff;
}

.landing-hero__visual .play-card__field {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 5;
    overflow: visible;
    -webkit-mask-image:
        linear-gradient(to bottom, transparent, #000 9%, #000 88%, transparent),
        linear-gradient(to right, transparent, #000 8%, #000 94%, transparent);
    -webkit-mask-composite: source-in;
    mask-image:
        linear-gradient(to bottom, transparent, #000 9%, #000 88%, transparent),
        linear-gradient(to right, transparent, #000 8%, #000 94%, transparent);
    mask-composite: intersect;
}
/* The yard lines, hashes and numbers are context, not content. */
.landing-hero__visual .play-card__field g[stroke="#ffffff"],
.landing-hero__visual .play-card__field g[fill="#ffffff"] { opacity: 0.3; }
.landing-hero__visual .play-card__field g[stroke="#f5c116"] { stroke-width: 2.6; }

.landing-hero__visual .play-card__name {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    margin: 0.35rem 0 0 0;
    justify-content: center;
}
.landing-hero__visual .play-card__name [data-hero-chip] {
    font-family: var(--font-display);
    font-size: 1.5rem;
    letter-spacing: 0.04em;
    color: var(--c-endzone);
}
.landing-hero__visual .play-card__meta {
    font-size: 0.85rem;
    color: rgba(250, 250, 247, 0.7);
}

@media (min-width: 960px) {
    .landing-hero { padding: 4.5rem 2.5rem 5rem; }
    .landing-hero__inner {
        grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
        gap: 3.5rem;
    }
    .landing-hero__demo { margin: 0; justify-self: end; }
}

/* The coach's call — the "words in" half of the hero. Large and readable,
   set like a message the coach just sent. */
.play-prompt {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.95rem 1.1rem;
    background: var(--c-chalk);
    color: var(--c-ink-900);
    border-radius: 16px 16px 16px 4px;
    box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
}
.play-prompt__badge {
    flex: none;
    margin-top: 0.1rem;
    padding: 0.2rem 0.55rem;
    border-radius: var(--r-pill);
    background: var(--c-field-900);
    color: #ffffff;
    font-size: 0.75rem;
    font-weight: 700;
}
.play-prompt__text {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    font-size: 1.1rem;
    font-weight: 500;
    line-height: 1.35;
}
.play-prompt__typed {
    display: inline-block;
    max-width: 30em;
    overflow: hidden;
    white-space: nowrap;
    vertical-align: bottom;
}
.play-prompt__caret {
    flex: none;
    width: 2px;
    height: 1.15em;
    margin-left: 2px;
    background: var(--c-field-700);
}

/* The "watch it draw itself" half: each route reveals itself by sliding
   its dash gap off the end of the path, then the arrowhead fades in.
   Pure CSS, looping. The default state is the *finished* play (routes
   drawn, arrows shown) so prefers-reduced-motion lands on a coherent
   static play; the no-preference block below hides them first, then loops
   the draw. */
/* Scoped to ``.landing`` so this self-drawing treatment never leaks onto
   the editor's (or the playbook thumbnails') ``.play-route`` polylines,
   which share the class name but must render as static, fully-drawn
   routes. */
.landing .play-route {
    stroke-dasharray: 240;
    stroke-dashoffset: 0;
}
.landing .play-arrow { opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
    .play-prompt__typed {
        max-width: 0;
        animation: prompt-type 6s ease-in-out infinite;
    }
    .play-prompt__caret {
        animation: prompt-caret 0.9s steps(1, end) infinite;
    }
    .landing .play-route {
        stroke-dashoffset: 240;
        animation: route-draw 6s ease-in-out infinite;
    }
    .landing .play-route--2 { animation-name: route-draw-2; }
    .landing .play-route--3 { animation-name: route-draw-3; }
    .landing .play-arrow {
        opacity: 0;
        animation: arrow-pop 6s ease-in-out infinite;
    }
    .landing .play-arrow--2 { animation-name: arrow-pop-2; }
    .landing .play-arrow--3 { animation-name: arrow-pop-3; }
}

@keyframes prompt-type {
    0%        { max-width: 0; }
    22%, 90%  { max-width: 30em; }
    97%, 100% { max-width: 0; }
}
@keyframes prompt-caret {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0; }
}
/* Each route stays hidden through the typing phase, draws in its own
   window (staggered), holds, then resets just before the loop. */
@keyframes route-draw {
    0%, 30%   { stroke-dashoffset: 240; }
    50%, 95%  { stroke-dashoffset: 0; }
    99%, 100% { stroke-dashoffset: 240; }
}
@keyframes route-draw-2 {
    0%, 36%   { stroke-dashoffset: 240; }
    56%, 95%  { stroke-dashoffset: 0; }
    99%, 100% { stroke-dashoffset: 240; }
}
@keyframes route-draw-3 {
    0%, 42%   { stroke-dashoffset: 240; }
    64%, 95%  { stroke-dashoffset: 0; }
    99%, 100% { stroke-dashoffset: 240; }
}
@keyframes arrow-pop {
    0%, 48%   { opacity: 0; }
    54%, 95%  { opacity: 1; }
    99%, 100% { opacity: 0; }
}
@keyframes arrow-pop-2 {
    0%, 54%   { opacity: 0; }
    60%, 95%  { opacity: 1; }
    99%, 100% { opacity: 0; }
}
@keyframes arrow-pop-3 {
    0%, 62%   { opacity: 0; }
    68%, 95%  { opacity: 1; }
    99%, 100% { opacity: 0; }
}

/* Calls to try — they drive the hero script (type the call, redraw). */
.play-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    margin: 0;
}
.play-chips__label {
    flex-basis: 100%;
    text-align: center;
    font-size: 0.85rem;
    color: rgba(250, 250, 247, 0.7);
}
.play-chip {
    min-height: 40px;
    padding: 0.4rem 0.95rem;
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 600;
    color: #ffffff;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.45);
    border-radius: var(--r-pill);
    cursor: pointer;
    transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.play-chip:hover { border-color: #ffffff; }
.play-chip:focus-visible { outline: 3px solid #ffffff; outline-offset: 2px; }
.play-chip.is-active {
    background: #ffffff;
    color: var(--c-field-900);
    border-color: #ffffff;
}

/* When the hero script is live it adds ``js-hero`` to <html>: hand the
   card's routes / arrows / prompt over to JS-driven transitions by
   switching off the CSS-only loop. */
.js-hero .landing-hero__visual .play-card .play-route,
.js-hero .landing-hero__visual .play-card .play-arrow { animation: none !important; }
.js-hero .play-prompt__typed {
    animation: none !important;
    max-width: none;
    white-space: normal;   /* JS types char-by-char; let it wrap instead of clip */
    overflow: visible;
}
.js-hero .play-prompt__text { display: block; }
.js-hero .play-prompt__typed { display: inline; }
.js-hero .play-prompt__caret { display: inline-block; vertical-align: text-bottom; }

/* --------------------------------------------------------------------
   5a. Landing — scroll-reveal motion (P1.1)

   Opt-in: the inline script adds ``.reveal-on`` to <html> only when
   motion is allowed and IntersectionObserver exists. With JS off or under
   prefers-reduced-motion the class is absent, so [data-reveal] elements
   render fully visible — the motion is purely additive.
   -------------------------------------------------------------------- */
.reveal-on [data-reveal] {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal-on [data-reveal].is-visible {
    opacity: 1;
    transform: none;
}
/* Cascade siblings inside the grids / CTA so they arrive in sequence. */
.reveal-on .step[data-reveal]:nth-child(2),
.reveal-on .ai-card[data-reveal]:nth-child(2),
.reveal-on .landing-cta__lede[data-reveal] { transition-delay: 0.08s; }
.reveal-on .step[data-reveal]:nth-child(3),
.reveal-on .ai-card[data-reveal]:nth-child(3),
.reveal-on .landing-cta .btn[data-reveal] { transition-delay: 0.16s; }

/* --------------------------------------------------------------------
   5a2. Landing — full-bleed action-photo band
   A breather between the abstract product hero and the "why it's
   different" pitch: a real game under a field-green scrim. The image
   covers a height-capped band (so a 16:9 shot never dominates on wide
   screens), the overlaid line sits bottom-left within the page gutter,
   and the end-zone hairline mirrors .landing-steps.
   -------------------------------------------------------------------- */

.landing-photo {
    position: relative;
    margin: 0;
    height: clamp(300px, 42vw, 520px);
    overflow: hidden;
    background: var(--c-field-900);
}
.landing-photo::before {
    /* End-zone hairline along the top — ties to .landing-steps. */
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 4px;
    background: var(--c-endzone);
    z-index: 3;
}
.landing-photo__img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 36%;   /* keep the runners, not the sky */
}
.landing-photo__scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        linear-gradient(90deg,
            rgba(7, 55, 31, 0.88) 0%,
            rgba(7, 55, 31, 0.55) 36%,
            rgba(7, 55, 31, 0.08) 66%,
            rgba(7, 55, 31, 0.00) 100%),
        linear-gradient(0deg,
            rgba(7, 55, 31, 0.45) 0%,
            rgba(7, 55, 31, 0.00) 45%);
}
.landing-photo__copy {
    position: absolute;
    inset: 0;
    z-index: 2;
    max-width: 1120px;
    margin: 0 auto;
    padding: 2.25rem 1.5rem;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}
.landing-photo .landing-eyebrow { color: var(--c-endzone); }
.landing-photo__line {
    margin: 0;
    max-width: 22ch;
    color: #ffffff;
    font-family: var(--font-display);
    font-size: clamp(1.7rem, 3.4vw + 0.5rem, 2.85rem);
    line-height: 1.02;
    letter-spacing: 0.01em;
    text-shadow: 0 2px 22px rgba(0, 0, 0, 0.45);
}

/* --------------------------------------------------------------------
   5b. Landing — "Not a drawing tool" positioning band
   -------------------------------------------------------------------- */

.landing-versus {
    background: color-mix(in srgb, var(--c-field-900) 4%, #ffffff);
    border-top: 1px solid var(--c-line);
    border-bottom: 1px solid var(--c-line);
    padding: 4rem 1.25rem;
}
.landing-versus__inner {
    max-width: 1120px;
    margin: 0 auto;
}
.landing-versus__head {
    max-width: 40rem;
    margin: 0 0 2rem 0;
}
.landing-versus__title {
    font-size: var(--t-section);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 800;
    margin: 0 0 0.85rem 0;
    color: var(--c-ink-900);
}
.landing-versus__lede {
    margin: 0;
    color: var(--c-ink-600);
    font-size: 1.05rem;
}

.versus-grid {
    display: grid;
    gap: 0.6rem;
}
.versus-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.5rem;
    background: var(--c-paper);
    border: 1px solid var(--c-line);
    border-radius: var(--r-card);
    padding: 1rem 1.1rem;
    box-shadow: var(--shadow-soft);
}
.versus-row--header { display: none; }
.versus-cell { font-size: 0.95rem; }
.versus-cell--label {
    font-weight: 700;
    color: var(--c-ink-900);
}
.versus-cell--them {
    color: var(--c-ink-600);
}
.versus-cell--them::before { content: "Drawing tools: "; font-weight: 700; color: var(--c-ink-400); }
.versus-cell--us {
    color: var(--c-ink-900);
    font-weight: 600;
}
.versus-cell--us::before {
    content: "AI Play Designer: ";
    font-weight: 700;
    color: var(--c-endzone-deep);
}

@media (min-width: 760px) {
    .versus-grid { gap: 0; }
    .versus-row {
        grid-template-columns: 1.1fr 1fr 1fr;
        align-items: center;
        gap: 1.25rem;
        border-radius: 0;
        border-bottom: none;
        box-shadow: none;
        padding: 1.1rem 1.35rem;
    }
    .versus-row:first-child { border-radius: var(--r-card) var(--r-card) 0 0; }
    .versus-row:last-child {
        border-bottom: 1px solid var(--c-line);
        border-radius: 0 0 var(--r-card) var(--r-card);
    }
    .versus-row--header {
        display: grid;
        background: var(--c-field-900);
        color: #ffffff;
    }
    .versus-row--header .versus-cell {
        font-size: 0.9rem;
        font-weight: 700;
    }
    .versus-row--header .versus-cell--us { color: var(--c-endzone); }
    /* "Drawing tools" header sat as dark-gray ink on the dark-green header
       band, so it read as nearly invisible. Give it a legible light chip that
       mirrors the "AI Play Designer" box geometry — neutral white for the
       competitor column, yellow for ours. */
    .versus-row--header .versus-cell--them {
        color: #ffffff;
        background: color-mix(in srgb, #ffffff 14%, transparent);
        border: 1px solid color-mix(in srgb, #ffffff 24%, transparent);
        border-radius: 8px;
        padding: 0.55rem 0.75rem;
        margin: -0.55rem -0.2rem;
    }
    /* On wide screens the column headers carry the labels, so drop the
       per-cell "Drawing tools:" / "AI Play Designer:" prefixes. */
    .versus-cell--them::before,
    .versus-cell--us::before { content: none; }
    .versus-cell--us {
        background: color-mix(in srgb, var(--c-endzone) 12%, #ffffff);
        border-radius: 8px;
        padding: 0.55rem 0.75rem;
        margin: -0.55rem -0.2rem;
    }
}

/* --------------------------------------------------------------------
   6. Landing — pillars, steps, final CTA
   -------------------------------------------------------------------- */

.landing-section {
    padding: 4rem 1.25rem;
    max-width: 1120px;
    margin: 0 auto;
}

.landing-section__head {
    max-width: 38rem;
    margin: 0 0 2.25rem 0;
}

.landing-section__title {
    font-size: var(--t-section);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 800;
    margin: 0 0 0.85rem 0;
    color: var(--c-ink-900);
}

.landing-section__lede {
    margin: 0;
    color: var(--c-ink-600);
    font-size: 1.05rem;
}

/* About page — contact + version cards under the "Who we are" lede. */
.about-meta {
    display: grid;
    gap: 1rem;
    margin-top: 2rem;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.about-card {
    border: 1px solid var(--c-line, #e2e8e6);
    border-radius: 12px;
    padding: 1.25rem 1.5rem;
    background: #fff;
}

.about-card__title {
    margin: 0 0 0.4rem;
    font-size: 1.1rem;
}

.about-card__body {
    margin: 0;
    color: var(--c-ink-600);
}

/* The About page's story and "what it does" paragraphs under the lede. */
.about-story {
    max-width: 44rem;
    margin: 0 0 2.5rem;
    color: var(--c-ink-600);
    line-height: 1.65;
}
.about-story p { margin: 0 0 1rem; }
.about-story__title {
    margin: 2rem 0 0.75rem;
    font-size: 1.25rem;
    color: var(--c-ink-900);
}

/* Everything else the product does: plain rows on hairlines, two columns
   on wide screens. The AI story has its own band above; these are the
   supporting features, so they stay quiet. */
.feature-list {
    display: grid;
    grid-template-columns: 1fr;
    column-gap: 3rem;
    border-top: 1px solid var(--c-line);
}
.feature {
    display: grid;
    grid-template-columns: 2rem 1fr;
    align-content: start;
    column-gap: 1rem;
    padding: 1.35rem 0;
    border-bottom: 1px solid var(--c-line);
}
.feature__icon {
    grid-row: span 2;
    padding-top: 0.1rem;
    color: var(--c-field-700);
}
.feature__icon svg { display: block; width: 24px; height: 24px; }
.feature__title {
    margin: 0 0 0.3rem 0;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--c-ink-900);
}
.feature__body {
    margin: 0;
    font-size: 0.97rem;
    line-height: 1.55;
    color: var(--c-ink-600);
}
@media (min-width: 760px) {
    .feature-list { grid-template-columns: 1fr 1fr; }
}

.landing-trust {
    padding: 3.25rem 1.25rem;
    background: var(--c-chalk);
    border-top: 1px solid var(--c-line);
}
.landing-trust__inner {
    max-width: 56rem;
    margin: 0 auto;
    text-align: center;
}
.landing-trust__eyebrow {
    margin: 0 0 1.25rem 0;
    font-family: var(--font-display);
    font-size: var(--t-eyebrow);
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--c-ink-400);
}
.trust-leagues {
    list-style: none;
    margin: 0 0 1.75rem 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.6rem 1rem;
}
.trust-leagues li {
    font-family: var(--font-display);
    font-size: 1.15rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--c-field-700);
    padding: 0.3rem 0.85rem;
    border: 1px solid var(--c-line);
    border-radius: var(--r-pill);
    background: var(--c-paper);
}
.trust-note {
    margin: 0;
    color: var(--c-ink-600);
    font-size: 1rem;
    line-height: 1.6;
}
.trust-note strong { color: var(--c-ink-900); }

/* --------------------------------------------------------------------
   Pricing page — Pro / Max / Enterprise tier cards
   -------------------------------------------------------------------- */
.pricing-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1.1rem;
    max-width: 1040px;
    margin: 2rem auto 0;
    align-items: stretch;
}

.price-card {
    background: var(--c-paper);
    border: 1px solid var(--c-line);
    border-radius: var(--r-card);
    padding: 1.6rem 1.5rem 1.7rem;
    box-shadow: var(--shadow-soft);
    display: flex;
    flex-direction: column;
    position: relative;
}
.price-card--featured {
    border-color: var(--c-field-700);
    border-width: 2px;
    box-shadow: var(--shadow-card);
}
.price-card--enterprise {
    background: var(--c-field-50);
}

.price-card__badge {
    position: absolute;
    top: -0.7rem;
    left: 1.5rem;
    background: var(--c-endzone);
    color: var(--c-ink-900);
    font-size: var(--t-eyebrow);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 0.25rem 0.6rem;
    border-radius: var(--r-pill);
}

.price-card__name {
    margin: 0 0 0.5rem 0;
    font-family: var(--font-display);
    font-size: 1.6rem;
    letter-spacing: 0.02em;
    color: var(--c-ink-900);
}

.price-card__price {
    margin: 0 0 0.75rem 0;
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
}
.price-card__amount {
    font-size: 2.4rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--c-ink-900);
    line-height: 1;
}
.price-card__amount--contact {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--c-field-700);
}
.price-card__interval {
    color: var(--c-ink-400);
    font-size: var(--t-meta);
}

.price-card__blurb {
    margin: 0 0 1rem 0;
    color: var(--c-ink-600);
    line-height: 1.5;
    font-size: 0.95rem;
}

.price-card__features {
    list-style: none;
    margin: 0 0 1.5rem 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex: 1 1 auto;
}
.price-card__features li {
    position: relative;
    padding-left: 1.4rem;
    color: var(--c-ink-900);
    font-size: 0.95rem;
    line-height: 1.4;
}
.price-card__features li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.4em;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--c-field-300);
}

/* Sprint 3: outcome-anchored breakdown nested inside the credit row
   on each price card. The bullet styling resets so the breakdown
   reads as a sub-list rather than a flat feature list. */
.price-card__outcomes {
    list-style: none;
    margin: 0.45rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.18rem;
}
.price-card__outcomes li {
    padding-left: 0;
    font-size: 0.84rem;
    font-weight: 500;
    color: var(--c-ink-600, #475569);
}
.price-card__outcomes li::before {
    /* Override the green dot — the sub-list reads tighter as plain
       text. */
    content: none;
}
.price-card__outcome-note {
    margin: 0.35rem 0 0;
    font-size: 0.78rem;
    line-height: 1.4;
    color: var(--c-ink-400, #94a3b8);
    font-style: italic;
}

.price-card__cta {
    width: 100%;
    justify-content: center;
}

.price-card__cta-form {
    /* Wraps the POST button for logged-in users; should not change the
       card's visual rhythm vs. the anchor variant used for anonymous
       visitors. */
    margin: 0;
}

/* The skip-the-trial offer, directly beneath the primary CTA.
   Two markup variants, ONE appearance on purpose: authed coaches get a
   ``<label>`` wrapping a checkbox (the POST form carries it), anonymous
   visitors get an ``<a>`` that rides the choice into signup on the query
   string. It is the same offer either way, so a coach must not perceive a
   difference between them.

   Styled as a quiet inset shelf rather than loose small print. Unstyled, an
   unconstrained three-line label sat flush against the CTA and read as a
   layout accident on the one surface where layout credibility converts. The
   shelf gives the offer a boundary of its own without competing with the
   button: chalk on paper, hairline border, meta-scale type. */
.price-card__skip-trial,
.price-card__skip-trial-link {
    display: block;
    margin: 0.6rem 0 0;
    padding: 0.6rem 0.7rem;
    background: var(--c-chalk);
    border: 1px solid var(--c-line);
    border-radius: var(--r-input);
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--c-ink-600);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

/* Checkbox on the first text line, not centred against the whole block —
   the copy wraps to three lines in a card this narrow. */
.price-card__skip-trial {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
}
.price-card__skip-trial input[type="checkbox"] {
    flex: 0 0 auto;
    width: 1rem;
    height: 1rem;
    /* Optical centre of the first line rather than its top edge. */
    margin: 0.12rem 0 0;
    accent-color: var(--c-field-700);
    cursor: pointer;
}

.price-card__skip-trial:hover,
.price-card__skip-trial-link:hover {
    border-color: var(--c-field-300);
    color: var(--c-ink-900);
}
.price-card__skip-trial-link:hover {
    text-decoration: underline;
}

/* Ticked reads as chosen. Decorative only, so browsers without ``:has()``
   lose nothing the checkbox itself doesn't already say. */
.price-card__skip-trial:has(input:checked) {
    background: var(--c-field-50);
    border-color: var(--c-field-500);
    color: var(--c-ink-900);
}

@media (prefers-reduced-motion: no-preference) {
    .price-card__skip-trial,
    .price-card__skip-trial-link {
        transition: background 140ms ease, border-color 140ms ease,
                    color 140ms ease;
    }
}

.pricing-error,
.pricing-success,
.pricing-notice {
    margin: 0 0 1.25rem 0;
    padding: 0.75rem 1rem;
    border: 1px solid;
    border-radius: var(--r-card);
    font-size: 0.95rem;
    max-width: 56rem;
}

.pricing-error {
    background: var(--c-error-bg);
    border-color: var(--c-error-line);
    color: var(--c-error-ink);
}

.pricing-success {
    /* Field-green wash — Checkout returned successfully, user is in. */
    background: var(--c-field-50);
    border-color: var(--c-field-300);
    color: var(--c-field-900);
}
.pricing-success a {
    color: var(--c-field-700);
    font-weight: 600;
    margin-left: 0.25rem;
}

.pricing-notice {
    /* End-zone yellow wash — payment didn't complete, gentle nudge. */
    background: color-mix(in srgb, var(--c-endzone) 18%, #ffffff);
    border-color: var(--c-endzone-deep);
    color: var(--c-ink-900);
}

/* Sign-up plan selector — radio cards reusing the auth-form field rhythm. */
.signup-plans {
    border: none;
    margin: 0;
    padding: 0;
}
.signup-plans legend {
    font-weight: 600;
    color: var(--c-ink-900);
    padding: 0;
    margin-bottom: 0.35rem;
}
/* Billing-interval toggle inside the sign-up plan picker. Reuses the
   .billing-toggle pills from the pricing page; just tightens the spacing so
   it sits neatly above the stacked tier cards. */
.billing-toggle--signup {
    justify-content: flex-start;
    gap: 0.6rem;
    margin: 0.35rem 0 0.85rem;
    flex-wrap: wrap;
}
/* The narrow sign-up card can be as little as ~240px wide, so let the two
   pills wrap instead of forcing the card (and the page) into a horizontal
   scroll at 320px. */
.billing-toggle--signup .billing-toggle__switch {
    flex-wrap: wrap;
    justify-content: center;
}

/* Sign-up plan picker — one selectable card per tier (Playbook / Coach /
   Program), stacked in the narrow auth card, with a Monthly/Annual toggle.
   Carries the pricing page's color language: featured green outline + a
   "Most popular" end-zone badge on Coach, a field-green wash on the checked
   card, and the yellow "2 months free" save line under the annual price. */
.plan-choice {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.7rem;
    margin: 0.4rem 0 0.5rem;
}
.plan-choice__option {
    position: relative;
    display: block;
    cursor: pointer;
}
.plan-choice__option input {
    position: absolute;
    opacity: 0;
    inset: 0;
    margin: 0;
    cursor: pointer;
}
.plan-choice__badge {
    position: absolute;
    top: -0.6rem;
    right: 0.9rem;
    z-index: 1;
    pointer-events: none;
    background: var(--c-endzone);
    color: var(--c-ink-900);
    font-size: var(--t-eyebrow);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 0.2rem 0.55rem;
    border-radius: var(--r-pill);
}
.plan-choice__body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    border: 1.5px solid var(--c-line);
    border-radius: var(--r-card);
    padding: 0.85rem 0.95rem;
    background: var(--c-paper);
    transition: border-color 140ms ease, background 140ms ease,
        box-shadow 140ms ease;
}
.plan-choice__option--featured .plan-choice__body {
    border-color: var(--c-field-700);
    border-width: 2px;
}
.plan-choice__option:hover .plan-choice__body {
    border-color: var(--c-field-300);
}
.plan-choice__option input:checked + .plan-choice__body {
    border-color: var(--c-field-700);
    background: var(--c-field-50);
    box-shadow: var(--shadow-soft);
}
.plan-choice__option input:focus-visible + .plan-choice__body {
    outline: 2px solid var(--c-field-300);
    outline-offset: 2px;
}
.plan-choice__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.2rem 0.75rem;
}
.plan-choice__name {
    font-family: var(--font-display);
    font-size: 1.2rem;
    letter-spacing: 0.02em;
    font-weight: 700;
    color: var(--c-ink-900);
}
.plan-choice__price {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem;
}
/* Keep the dollar figure itself intact; only the "/ mo, billed annually"
   suffix may wrap, so the price never forces the card past a 320px viewport. */
.plan-choice__amount {
    white-space: nowrap;
}
.plan-choice__amount {
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1;
    color: var(--c-ink-900);
}
.plan-choice__interval {
    font-size: var(--t-meta);
    color: var(--c-ink-400);
}
.plan-choice__save {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--c-field-700);
}
/* Monthly view has no annual discount to advertise — keep the line's
   height so cards don't jump when toggling, just hide the text. */
.plan-choice.is-monthly .plan-choice__save {
    visibility: hidden;
}
.plan-choice__meta {
    font-size: var(--t-meta);
    color: var(--c-ink-600);
}
/* Sprint 3: outcome-anchored breakdown next to credit count in
   the signup plan picker. */
.plan-choice__outcomes {
    display: block;
    margin-top: 0.18rem;
    font-size: 0.78rem;
    color: var(--c-ink-400, #94a3b8);
    line-height: 1.4;
}

/* AI-credit indicator (editor toolbar). Populated by the editor bundle. */
.credits-indicator {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0.75rem 0;
    padding: 0.4rem 0.75rem;
    border: 1px solid var(--c-line);
    border-radius: var(--r-pill);
    background: var(--c-paper);
    font-size: var(--t-meta);
}
.credits-indicator[data-state="exhausted"] {
    border-color: var(--c-error-line);
    background: var(--c-error-bg);
}
.credits-indicator__label {
    color: var(--c-ink-700, var(--c-ink-900));
    font-weight: 600;
}
.credits-indicator__label--empty {
    color: var(--c-error-ink);
}
.credits-indicator__cta {
    font-weight: 600;
    color: var(--c-field-700);
    white-space: nowrap;
}
/* Sprint 3: outcome-anchored secondary line under the credit count.
   Visually quiet — italic + smaller + muted — so it reads as
   supplemental info, not a primary status. */
.credits-indicator__outcomes {
    margin-left: 0.55rem;
    color: var(--c-ink-400, #94a3b8);
    font-size: 0.78rem;
    font-style: italic;
    white-space: nowrap;
}

/* "How it works" — three numbered steps with end-zone-yellow numerals. */
.landing-steps {
    background: var(--c-field-900);
    color: #ffffff;
    border-radius: 0;
    margin: 0;
    padding: 4rem 1.25rem;
    position: relative;
    overflow: hidden;
}
.landing-steps::before {
    /* Decorative yard-line band along the top, end-zone yellow. */
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: var(--c-endzone);
}

.landing-steps::after {
    /* Cinematic vignette — deepens the turf toward the edges so the
       glowing routes and step cards float. Sits above the turf motif
       (z 0) but below the content (z 2). */
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(120% 75% at 50% 0%,
                transparent 42%, rgba(0, 0, 0, 0.38) 100%);
}

.landing-steps__inner {
    position: relative;
    z-index: 2;
    max-width: 1120px;
    margin: 0 auto;
}

.landing-steps .landing-eyebrow { color: var(--c-endzone); }
.landing-steps .landing-section__title { color: #ffffff; }
.landing-steps .landing-section__lede { color: rgba(255, 255, 255, 0.78); }

.step-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 1.5rem;
    counter-reset: steps;
}

.step { position: relative; }

/* Same scoreboard numerals as the pre-game rep band. */
.step__num {
    display: block;
    margin-bottom: 0.9rem;
    font-family: var(--font-display);
    font-size: 3.5rem;
    line-height: 0.9;
    color: var(--c-endzone);
}

/* Tiny self-drawing route accent in each step card's corner — the brand
   motion motif, threaded through "how it works". Reuses the .play-route /
   .play-arrow keyframes (dasharray inherited from .play-route). */
.step__route {
    position: absolute;
    top: 1.45rem;
    right: 1.35rem;
    width: 64px;
    height: 24px;
}
.step__route .play-route {
    stroke: var(--c-endzone);
    stroke-width: 3;
    filter: drop-shadow(0 0 4px rgba(245, 193, 22, 0.5));
}
.step__route .play-arrow { fill: var(--c-endzone); }

.step__title {
    margin: 0 0 0.4rem 0;
    font-size: 1.15rem;
    font-weight: 700;
    color: #ffffff;
    letter-spacing: -0.01em;
}

.step__body {
    margin: 0;
    color: rgba(255, 255, 255, 0.78);
    line-height: 1.55;
    font-size: 0.98rem;
}

/* Final CTA band — chalk surface with a single dominant action. */
.landing-cta {
    padding: 4.5rem 1.25rem 5rem;
    text-align: center;
    background: var(--c-chalk);
    position: relative;
}

.landing-cta__title {
    margin: 0 0 0.75rem 0;
    font-size: var(--t-section);
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 800;
    color: var(--c-ink-900);
}

.landing-cta__lede {
    margin: 0 auto 1.75rem auto;
    max-width: 34rem;
    color: var(--c-ink-600);
    font-size: 1.05rem;
}

/* Primary + secondary CTA, centered and wrapping on narrow screens. */
.landing-cta__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem;
}

/* Pricing transparency teaser under the CTA (P2). */
.landing-cta__pricing {
    margin: 1.1rem 0 0 0;
    font-size: 0.92rem;
    color: var(--c-ink-600);
}
.landing-cta__pricing strong { color: var(--c-ink-900); }

/* --------------------------------------------------------------------
   Landing — game-day payoff: wristband mockup (P1.2, wristband half)
   -------------------------------------------------------------------- */
.landing-wristband {
    background: color-mix(in srgb, var(--c-field-900) 4%, #ffffff);
    border-top: 1px solid var(--c-line);
    border-bottom: 1px solid var(--c-line);
    padding: 4rem 1.25rem;
}
.landing-wristband__inner {
    max-width: 1120px;
    margin: 0 auto;
    display: grid;
    gap: 2.5rem;
    align-items: center;
}
.landing-wristband__points {
    margin: 1.25rem 0 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 0.5rem;
}
.landing-wristband__points li {
    position: relative;
    padding-left: 1.4rem;
    color: var(--c-ink-700, var(--c-ink-600));
}
.landing-wristband__points li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.5em;
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 2px;
    background: var(--c-endzone);
}
.landing-wristband__visual {
    display: flex;
    justify-content: center;
}

/* The artifact: an elastic band (two straps) framing a laminated play
   sheet. Tilted slightly so it reads as a worn wristband, not a table. */
.wristband {
    width: 300px;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    transform: rotate(3deg);
    filter: drop-shadow(0 18px 30px rgba(7, 24, 14, 0.22));
}
.wristband__strap {
    width: 72%;
    height: 22px;
    background: linear-gradient(var(--c-field-700), var(--c-field-900));
    border-radius: 6px;
}
.wristband__sheet {
    width: 100%;
    background: #ffffff;
    border: 1px solid var(--c-line);
    border-radius: 12px;
    padding: 0.85rem;
    margin: -4px 0;
    z-index: 1;
}
.wristband__title {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    font-size: 0.74rem;
    color: var(--c-field-900);
    padding-bottom: 0.5rem;
    margin-bottom: 0.55rem;
    border-bottom: 2px solid var(--c-endzone);
}
.wristband__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.4rem;
}
.wristband__cell {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    border: 1px solid var(--c-line);
    border-radius: 6px;
    padding: 0.3rem 0.35rem;
    background: var(--c-paper);
}
.wristband__num {
    font-family: var(--font-display);
    font-size: 0.92rem;
    color: var(--c-field-700);
    line-height: 1;
}
.wristband__route { width: 22px; height: 24px; display: block; }

@media (min-width: 760px) {
    .landing-wristband__inner { grid-template-columns: 1.05fr 0.95fr; }
}

/* --------------------------------------------------------------------
   11. Auth pages (sign-in, sign-up, verify, reset)
   --------------------------------------------------------------------
   The landing has its own bespoke layout (sections 5-6 above). These
   rules style the smaller card-on-page auth surfaces and inherit the
   new tokens automatically.
   ----------------------------------------------------------------- */

.auth-card {
    background: var(--c-paper);
    border: 1px solid var(--c-line);
    border-radius: var(--r-card);
    padding: 1.75rem 1.5rem;
    margin: 1.5rem auto;
    max-width: 440px;
    box-shadow: var(--shadow-soft);
    /* B-025: a long email / token in a message must wrap, not overflow,
       at narrow widths (down to 320px). The card is already fluid
       (max-width, not a fixed width). */
    overflow-wrap: break-word;
}

.auth-card--narrow {
    max-width: 380px;
    text-align: center;
}

.auth-card__title {
    margin: 0 0 0.5rem 0;
    font-size: 1.4rem;
    line-height: 1.25;
    font-weight: 800;
    letter-spacing: -0.015em;
}

.auth-card__lede {
    margin: 0 0 1.25rem 0;
    color: var(--c-ink-600);
    font-size: 0.97rem;
}

.auth-card__hint {
    margin: 1rem 0 0 0;
    font-size: var(--t-meta);
    color: var(--c-ink-600);
}

/* Honest email-failure UX (P0-10): the always-on "Didn't get it?" block on
   the sent pages, and the slim degraded-delivery notice above the GET forms. */
.auth-card__fallback {
    margin: 1.25rem 0 0 0;
    padding: 0.9rem 1rem;
    text-align: left;
    border: 1px solid var(--c-line, #e3e9e5);
    border-radius: var(--r-input, 10px);
    background: var(--c-bg, #f7faf8);
}
.auth-card__fallback h2 {
    margin: 0 0 0.5rem 0;
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--c-ink-900);
}
.auth-card__fallback ul {
    margin: 0;
    padding-left: 1.1rem;
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--c-ink-600);
}
.auth-card__fallback li + li {
    margin-top: 0.35rem;
}

.auth-card__notice {
    margin: 0 0 1.25rem 0;
    padding: 0.7rem 0.85rem;
    text-align: left;
    font-size: 0.9rem;
    line-height: 1.45;
    color: #7a4a05;
    background: #fdf3e0;
    border: 1px solid #f0d9a8;
    border-radius: var(--r-input, 10px);
}

/* Sprint 2: Google + Apple SSO buttons on login + signup. The buttons
   render above the email form and degrade to email-only when no
   provider is configured (no env vars → no DOM at all). */
.auth-sso {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin: 0 0 1.25rem;
}
.auth-sso__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.65rem;
    padding: 0.65rem 0.9rem;
    border-radius: var(--r-input, 0.5rem);
    border: 1px solid var(--c-line, #d1d5db);
    background: var(--c-paper, #fff);
    color: var(--c-ink-900, #0f172a);
    font-size: 0.95rem;
    font-weight: 600;
    text-decoration: none;
    transition: background 0.15s ease, border-color 0.15s ease;
}
.auth-sso__btn:hover {
    background: #f8fafc;
    border-color: #94a3b8;
}
.auth-sso__btn--apple {
    background: #000;
    color: #fff;
    border-color: #000;
}
.auth-sso__btn--apple:hover {
    background: #1a1a1a;
    border-color: #1a1a1a;
}
.auth-sso__divider {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    margin: 0.25rem 0 0;
    color: var(--c-ink-400, #94a3b8);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
.auth-sso__divider::before,
.auth-sso__divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--c-line, #e5e7eb);
}

/* Helper line under the signup SSO block telling the coach a plan step
   comes next (so "pick plan → Continue with Google" no longer feels like
   it silently dropped the choice). */
.auth-sso__hint {
    margin: 0.5rem 0 0;
    color: var(--c-ink-400, #94a3b8);
    font-size: 0.82rem;
    text-align: center;
}

/* Password field + inline Show/Hide reveal toggle. The input keeps its
   own styling; the toggle button is layered at the trailing edge. The
   button is rendered ``hidden`` and only un-hidden by the page's inline
   script, so there is no dead control when JS is off. */
.auth-field__password {
    position: relative;
    display: flex;
    align-items: stretch;
}
.auth-field__password input {
    flex: 1;
    /* Leave room for the toggle so long passwords don't slide under it. */
    padding-right: 4rem;
}
.auth-field__password-toggle {
    position: absolute;
    top: 50%;
    right: 0.4rem;
    transform: translateY(-50%);
    border: 0;
    background: transparent;
    color: var(--c-accent-700, #1f6f2b);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    padding: 0.25rem 0.4rem;
}
.auth-field__password-toggle:hover {
    text-decoration: underline;
}

/* Group the "Stay signed in" checkbox with the Sign-in button so the
   two read as one decision row rather than the checkbox floating under
   the field stack. */
.auth-form__submit-row {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.auth-card__actions {
    margin: 1.5rem 0 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.auth-form__error {
    margin: 0;
    padding: 0.7rem 0.9rem;
    background: var(--c-error-bg);
    border: 1px solid var(--c-error-line);
    color: var(--c-error-ink);
    border-radius: var(--r-input);
    font-size: 0.9rem;
}

.auth-field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.auth-field--row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}

.auth-field--checkbox {
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.9rem;
    color: var(--c-ink-900);
}

.auth-field label {
    font-size: var(--t-meta);
    font-weight: 600;
    color: var(--c-ink-900);
}

.auth-field input[type="email"],
.auth-field input[type="password"],
.auth-field input[type="text"],
.auth-field input[type="tel"] {
    font: inherit;
    padding: 0.65rem 0.8rem;
    border: 1px solid var(--c-line);
    border-radius: var(--r-input);
    background: var(--c-paper);
    color: var(--c-ink-900);
    width: 100%;
    min-height: 44px;
    transition: border-color 120ms ease, box-shadow 120ms ease;
}

.auth-field input:focus {
    outline: none;
    border-color: var(--c-field-500);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--c-field-500) 25%, transparent);
}

.auth-field__hint {
    margin: 0;
    font-size: 0.8rem;
    color: var(--c-ink-600);
    font-weight: 400;
}

.auth-field__error {
    margin: 0;
    color: var(--c-error-ink);
    font-size: 0.85rem;
}

/* Top-of-form error summary. The inline per-field messages are easy to miss
   on a long form after a 400 re-render (the browser returns to scroll-top),
   so every problem is also listed here, above the first control. */
.auth-form-errors {
    margin: 0 0 1.5rem;
    padding: 0.9rem 1.1rem;
    background: var(--c-error-bg);
    color: var(--c-error-ink);
    border: 1px solid var(--c-error-ink);
    border-radius: var(--r-tile, 0.75rem);
}
.auth-form-errors:focus { outline: none; }
.auth-form-errors__title {
    margin: 0 0 0.4rem;
    font-weight: 700;
    font-size: 0.92rem;
}
.auth-form-errors__list {
    margin: 0;
    padding-left: 1.2rem;
    font-size: 0.88rem;
    line-height: 1.5;
}
.auth-form-errors__list a { color: inherit; }

.auth-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0.65rem 1.3rem;
    border-radius: var(--r-pill);
    border: 1.5px solid var(--c-line);
    background: var(--c-paper);
    color: var(--c-ink-900);
    font-weight: 600;
    text-decoration: none;
    line-height: 1;
    transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}

.auth-button:hover,
.auth-button:focus {
    background: var(--c-field-50);
    border-color: var(--c-field-300);
    text-decoration: none;
}

.auth-button--primary {
    background: var(--c-field-700);
    border-color: var(--c-field-700);
    color: #ffffff;
}

.auth-button--primary:hover,
.auth-button--primary:focus {
    background: var(--c-field-500);
    border-color: var(--c-field-500);
    color: #ffffff;
}

button.auth-button { cursor: pointer; }

/* --------------------------------------------------------------------
   12. Responsive breakpoints
   -------------------------------------------------------------------- */

@media (min-width: 600px) {
    .playbook-list { grid-template-columns: repeat(2, 1fr); }
    /* Skip the thumbnail variant — it sets its own auto-fill grid
       (~10 columns at the 1120px ``app-main`` width) so the playbook
       detail packs ~12 plays into a single row. Without ``:not()``
       this 2-column rule would override the thumbnail grid because
       both selectors have the same specificity and this one comes
       later in the cascade. */
    .play-list:not(.play-list--thumbnails) { grid-template-columns: repeat(2, 1fr); }
    .play-field-container { max-width: 480px; }

    .step-list   { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 768px) {
    .playbook-list { grid-template-columns: repeat(3, 1fr); }
    .play-list:not(.play-list--thumbnails) { grid-template-columns: repeat(2, 1fr); }
    .play-field-container { max-width: 540px; }

    .app-header { padding: 1rem 1.5rem; }
    .app-main { padding: 1.5rem; }

    .landing-section { padding: 5.5rem 2rem; }
    .landing-steps   { padding: 5.5rem 2rem; }
    .landing-cta     { padding: 6rem 2rem; }

}


/* --------------------------------------------------------------------
    Print — every page: no header, white sheet, no shell padding
   -------------------------------------------------------------------- */
@media print {
    .app-header,
    .app-shell > .app-header,
    .print-screen-only,
    #teascan-offline-banner { display: none !important; }
    body { background: #fff; }
    .app-shell,
    .app-main { margin: 0 !important; padding: 0 !important; max-width: none !important; box-shadow: none !important; }
}

/* --------------------------------------------------------------------------
   Global footer (legal links on every page) + legal page body.
   -------------------------------------------------------------------------- */
.app-footer {
    margin-top: 3rem;
    padding: 1.5rem 1.25rem 2rem;
    border-top: 1px solid #e2e8f0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    color: #64748b;
    font-size: 0.85rem;
}
.app-footer__links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
}
.app-footer__links a {
    color: #475569;
    text-decoration: none;
}
.app-footer__links a:hover {
    text-decoration: underline;
}
.app-footer__copy {
    margin: 0;
    color: var(--c-ink-400);
}

/* Legal pages (Privacy / Terms): readable long-form column. */
.legal-body {
    max-width: 70ch;
    margin: 1.5rem auto 0;
    color: #334155;
    line-height: 1.6;
}
.legal-body h2 {
    margin: 1.75rem 0 0.5rem;
    font-size: 1.05rem;
    color: #0f172a;
}
.legal-body ul {
    margin: 0.5rem 0 0.5rem 1.25rem;
    padding: 0;
}
.legal-body li {
    margin: 0.35rem 0;
}

/* Roster game-day check-in (Feature 1). Sits above the player list
   on the roster detail page so the coach can flip the whole roster
   at once, then mark individual absences. The "OUT" badge greys
   out a player row without removing it. */
.roster-checkin {
    margin: 0.75rem 0 1rem;
    padding: 0.7rem 1rem;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: 0.5rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    justify-content: space-between;
}
.roster-checkin__head {
    display: flex;
    align-items: baseline;
    gap: 0.65rem;
}
.roster-checkin__title {
    margin: 0;
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #475569;
    font-weight: 700;
}
.roster-checkin__count {
    margin: 0;
    color: #0f172a;
    font-size: 0.9rem;
}
.roster-checkin__count strong {
    font-weight: 700;
    color: #16a34a;
}
.roster-checkin__bulk {
    display: flex;
    gap: 0.5rem;
}
.roster-checkin__out-badge {
    background: #94a3b8;
    color: #ffffff;
    font-size: 0.65rem;
    padding: 0.05rem 0.35rem;
    border-radius: 0.2rem;
    margin-left: 0.45rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    vertical-align: middle;
}
.play-list__item--unavailable .play-list__name {
    color: #94a3b8;
    text-decoration: line-through;
    text-decoration-color: #cbd5e1;
}

/* Quarter scheduler grid (Roster / Schedule). Rows are quarters,
   columns are position slots. Wrapped in an overflow container so
   a 9v9 schedule with 8 quarters can scroll horizontally on a
   phone without crowding the cells. */
.schedule-grid-wrap {
    overflow-x: auto;
    margin: 0.75rem 0;
    border: 1px solid #e2e8f0;
    border-radius: 0.5rem;
    background: #ffffff;
}
.schedule-grid {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
.schedule-grid th,
.schedule-grid td {
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid #e2e8f0;
    text-align: left;
}
.schedule-grid thead th {
    background: #f1f5f9;
    color: #0f172a;
    font-weight: 700;
    text-transform: uppercase;
    font-size: 0.75rem;
    letter-spacing: 0.04em;
}
.schedule-grid tbody th {
    background: #f8fafc;
    font-weight: 700;
    color: #1e3a8a;
    white-space: nowrap;
}
.schedule-grid select {
    width: 100%;
    min-width: 9rem;
    padding: 0.3rem 0.4rem;
    border: 1px solid #cbd5e1;
    border-radius: 0.3rem;
    background: #ffffff;
    font-size: 0.85rem;
}
.schedule-grid select.schedule-cell--conflict {
    /* Two cells in the same quarter point to the same player —
       the server will reject this on save (422). Paint the cell so
       the coach sees the issue before submitting. */
    border-color: #dc2626;
    background: #fef2f2;
    color: #b91c1c;
    box-shadow: 0 0 0 1px #dc2626 inset;
}

/* First-run editor tour (S1). Modal overlay that walks a new coach
   through the four core moves on initial editor load; self-gates
   via localStorage so it never reappears. */
.editor-tour {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 1rem;
}
.editor-tour__card {
    background: #ffffff;
    border-radius: 0.75rem;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.35);
    padding: 1.5rem;
    max-width: 28rem;
    width: 100%;
}
.editor-tour__title {
    margin: 0 0 0.5rem;
    font-size: 1.25rem;
    color: #0f172a;
    font-weight: 700;
}
.editor-tour__body {
    margin: 0 0 0.85rem;
    color: #475569;
    font-size: 0.9rem;
    line-height: 1.5;
}
.editor-tour__progress {
    margin: 0 0 1.1rem;
    color: #94a3b8;
    font-size: 0.75rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}
.editor-tour__actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
}
.editor-tour__btn {
    padding: 0.55rem 1rem;
    border-radius: 0.4rem;
    border: 1px solid transparent;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}
.editor-tour__btn--ghost {
    background: transparent;
    color: #475569;
    border-color: #cbd5e1;
}
.editor-tour__btn--ghost:hover {
    background: #f1f5f9;
}
.editor-tour__btn--primary {
    background: #1e3a8a;
    color: #ffffff;
}
.editor-tour__btn--primary:hover {
    background: #1e40af;
}

/* Schedule v2: transposed grid (slots-as-rows / quarters-as-columns),
   bench row, settings disclosure, print layout. */
.schedule-settings {
    margin: 0.75rem 0;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: 0.5rem;
    padding: 0.5rem 0.85rem;
}
.schedule-settings__summary {
    cursor: pointer;
    font-weight: 600;
    color: #1e3a8a;
}
.schedule-settings__form { margin-top: 0.75rem; }
.schedule-settings__labels {
    margin: 0.75rem 0;
    padding: 0.5rem 0.85rem;
    border: 1px solid #cbd5e1;
    border-radius: 0.5rem;
}
.schedule-settings__labels legend {
    padding: 0 0.4rem;
    font-weight: 600;
    color: #475569;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.schedule-bench-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-right: 0.5rem;
    font-size: 0.9rem;
    color: #475569;
    cursor: pointer;
}
.schedule-grid__bench th,
.schedule-grid__bench td {
    background: #fef3c7;
    font-size: 0.8rem;
    color: #78350f;
}

/* Wristband Q-card (item B). One card per quarter; the outer
   .wristband-sheet + .wristband-card containers come from the
   playbook wristband template so the cut/bleed pattern matches. */
.schedule-q-card__inner {
    display: flex;
    flex-direction: column;
    height: 100%;
    padding: 0.2in;
}
.schedule-q-card__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    border-bottom: 1px solid #cbd5e1;
    padding-bottom: 0.1in;
    margin-bottom: 0.1in;
}
.schedule-q-card__title {
    font-size: 1.1rem;
    font-weight: 800;
    color: #1e3a8a;
    letter-spacing: 0.04em;
}
.schedule-q-card__sub {
    font-size: 0.65rem;
    color: #475569;
}
.schedule-q-card__lineup {
    list-style: none;
    padding: 0;
    margin: 0;
    flex: 1;
}
.schedule-q-card__row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.05in 0;
    border-bottom: 1px dotted #e2e8f0;
    font-size: 0.8rem;
}
.schedule-q-card__slot {
    font-weight: 700;
    color: #0f172a;
}
.schedule-q-card__player {
    color: #1e3a8a;
}

/* Print: default to landscape so a 4-quarter / 9v9 grid fits a
   page without scaling. Hide all interactive chrome — only the
   title, summary line, and the grid (including bench if toggled
   on) should render on paper. */
@media print {
    @page {
        size: landscape;
        margin: 0.4in;
    }
    body { background: #ffffff; }
    .schedule-screen-only { display: none !important; }
    .schedule-page--print .schedule-screen-only { display: none !important; }
    .schedule-grid select {
        border: none;
        background: transparent;
        appearance: none;
        -webkit-appearance: none;
        padding: 0.1rem 0.2rem;
        min-width: 0;
        font-size: 0.85rem;
    }
    .schedule-grid-wrap { border: none; overflow: visible; }
    .schedule-grid th, .schedule-grid td { padding: 0.3rem 0.4rem; }
    /* Hide the global nav / header so paper doesn't waste space on
       links the coach can't tap. */
    nav, header.app-header { display: none !important; }
    /* ...and the global footer, for a stronger reason than wasted space: it
       is a block AFTER the last band, so once the bands fill a sheet it gets
       pushed onto a sheet of its OWN. A wristband print came out as
       "bands + one page holding nothing but '(c) Teascan LLC'" — a whole
       wasted sheet on every print. The legal links it carries are a
       requirement of the public SITE, not of a printed wristband. */
    footer.app-footer { display: none !important; }
    /* Keep the position chip's FILL when printing. Browsers drop backgrounds
       by default, which would silently return the printed schedule to the
       plain text the chip replaced.

       Lives in THIS block rather than a new trailing ``@media print`` of its
       own: ``tests/test_print_pages.py`` reads the LAST top-level print block,
       so appending one displaced the footer rule and failed the check that
       stops the site footer claiming its own sheet. One print block is also
       simply easier to reason about. */
    .slot-chip {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* ---- Keep each side's grid WHOLE ------------------------------------
       A grid split across a page fold is unusable on a sideline. Both sections
       share a sheet when they fit; the defense takes its own when they do not.
       ``break-inside`` is the modern property and ``page-break-inside`` the one
       older Chrome honours — both, because this only matters on paper and a
       silent no-op there is invisible until a coach prints. */
    .schedule-sheet {
        break-inside: avoid;
        page-break-inside: avoid;
    }
    /* No forced break BETWEEN them: that would always cost two sheets, and the
       owner asked for one sheet where one is enough. */

    /* ---- Per-sheet header ---------------------------------------------- */
    .schedule-print-head {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 0.6rem;
        margin: 0 0 0.35rem;
        padding-bottom: 0.2rem;
        border-bottom: 1px solid #111827;
        font-size: 0.8rem;
        color: #111827;
    }
    .schedule-print-head__left,
    .schedule-print-head__right {
        display: flex;
        align-items: baseline;
        gap: 0.5rem;
        min-width: 0;
    }
    .schedule-print-head__name { font-weight: 700; }
    /* The size sits BESIDE the date, per the owner, so one glance answers
       "which game, and how many a side". */
    .schedule-print-head__meta { white-space: nowrap; }
    /* Far right corner: the team, then the sheet index. */
    .schedule-print-head__team { font-weight: 700; }
    .schedule-print-head__page { font-variant-numeric: tabular-nums; }
    /* Set by the page when both grids share ONE sheet: a second header on the
       same sheet is the visible bug. A class rather than an inline style so the
       rule above can still turn the header on. */
    .schedule-print-head--dup { display: none !important; }

    /* The page title and summary line are redundant once every sheet carries
       its own header, and they cost the first sheet two lines of grid. */
    .playbook-detail__title, .game-day__sub { display: none !important; }

    /* ---- GRID MARKS (opt-in) -------------------------------------------
       Off: the clean read-only sheet this has always printed. On: every cell
       is ruled so a coach can write in it on the field. Scoped to a class the
       page sets from the checkbox, so it cannot change the screen. */
    .schedule-grid-marks .schedule-grid,
    .schedule-grid-marks .schedule-grid th,
    .schedule-grid-marks .schedule-grid td {
        border: 1px solid #111827 !important;
        border-collapse: collapse;
    }
    .schedule-grid-marks .schedule-grid { border-width: 2px !important; }
    /* Give a written-in cell room, and keep the borderless <select> from
       hiding the rule it now sits inside. */
    .schedule-grid-marks .schedule-grid td { padding: 0.45rem 0.4rem; }
    .schedule-grid-marks .schedule-grid-wrap { border: none; }
}

/* --------------------------------------------------------------------
   Landing — THE AI EDGE (three differentiators on midnight turf)
   -------------------------------------------------------------------- */
.ai-card-grid{display:grid;gap:2.25rem;grid-template-columns:1fr;margin-top:1rem}
.ai-card{position:relative}
/* Step number in scoreboard type: the three are done in this order. */
.ai-card__index{display:block;margin-bottom:.9rem;font-family:var(--font-display);font-size:3.5rem;line-height:.9;color:var(--c-endzone)}
.ai-card__motif{width:120px;height:96px;margin-bottom:1rem}
.ai-card__motif .ai-motif{width:120px;height:96px;display:block}
.ai-card__title{margin:0 0 .5rem 0;font-size:1.3rem;font-weight:700;letter-spacing:-.01em;color:#fff}
.ai-card__body{margin:0;color:rgba(255,255,255,.8);line-height:1.55;font-size:.95rem}
.ai-motif__prompt{fill:rgba(255,255,255,.1);stroke:rgba(255,255,255,.22);stroke-width:1}
.ai-motif__prompt-text{stroke:rgba(255,255,255,.55);stroke-width:2;stroke-linecap:round}
.ai-motif__route{stroke:var(--c-endzone);stroke-width:3;filter:drop-shadow(0 0 4px rgba(245,193,22,.5))}
.ai-motif__route--weak{stroke:rgba(255,255,255,.32);filter:none}
.ai-motif__arrow{fill:var(--c-endzone)}
.ai-motif__dot{fill:#fff}
.ai-motif__flag{fill:none;stroke:var(--c-endzone);stroke-width:2;opacity:.9}
.ai-motif__flag-mark{stroke:var(--c-endzone);stroke-width:2.4;stroke-linecap:round}
.ai-motif__zone{stroke-width:1}
.ai-motif__zone--beats{fill:color-mix(in srgb,var(--c-field-300) 30%,transparent);stroke:color-mix(in srgb,var(--c-field-300) 60%,transparent)}
.ai-motif__zone--stuffs{fill:rgba(214,39,40,.22);stroke:rgba(214,39,40,.5)}
.ai-motif__tag{font-family:var(--font-display);font-size:8px;letter-spacing:.12em;text-anchor:middle}
.ai-motif__tag--beats{fill:var(--c-field-300)}
.ai-motif__tag--stuffs{fill:#f0a3a3}
@media (prefers-reduced-motion:no-preference){.ai-motif__flag{animation:ai-flag-pulse 2.4s ease-in-out infinite}}
@keyframes ai-flag-pulse{0%,100%{opacity:.45;transform:scale(.92);transform-origin:96px 58px}50%{opacity:1;transform:scale(1.08);transform-origin:96px 58px}}
@media (min-width:760px){.ai-card-grid{grid-template-columns:repeat(3,1fr);gap:3rem}}

/* --------------------------------------------------------------------
   Landing — PLANS TEASER (compact 4-tier summary)
   -------------------------------------------------------------------- */
.plan-mini-grid{list-style:none;margin:0 0 1.4rem 0;padding:0;display:grid;gap:.85rem;grid-template-columns:repeat(2,1fr)}
.plan-mini{position:relative;background:var(--c-paper);border:1px solid var(--c-line);border-radius:var(--r-card);box-shadow:var(--shadow-soft);padding:1.1rem 1.1rem 1.15rem;display:flex;flex-direction:column;gap:.3rem}
.plan-mini--featured{border-color:var(--c-field-700);border-width:2px;box-shadow:var(--shadow-card)}
.plan-mini__badge{position:absolute;top:-.65rem;left:1rem;background:var(--c-endzone);color:var(--c-ink-900);font-family:var(--font-sans);font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;padding:.2rem .55rem;border-radius:var(--r-pill)}
.plan-mini__name{font-family:var(--font-display);font-size:1.25rem;letter-spacing:.02em;color:var(--c-ink-900)}
.plan-mini__price{font-size:1.5rem;font-weight:800;letter-spacing:-.02em;color:var(--c-ink-900);line-height:1}
.plan-mini__price small{font-size:.8rem;font-weight:600;color:var(--c-ink-400);letter-spacing:0}
.plan-mini__ai{font-size:.82rem;font-weight:600;color:var(--c-field-700)}
.plan-mini__ai--off{color:var(--c-ink-400);font-weight:500}
/* Trial eligibility, per teaser card. Quieter than the credit line above it —
   it qualifies the price rather than selling the plan — and the --off variant
   is the same muted ink as .plan-mini__ai--off so "no AI" and "no trial" read
   as the same kind of statement. */
.plan-mini__trial{font-size:.78rem;font-weight:500;color:var(--c-ink-600)}
.plan-mini__trial--off{color:var(--c-ink-400)}
/* Game-plan verdict chips. Without these both states rendered in the
   identical .play-list__kind palette, so "Worked" and "Didn't work" were
   indistinguishable at a glance — on a sheet whose whole job is being read at
   a glance. Green/amber on the same muted weight as the Called chip. */
.play-list__kind[data-state="worked"]{color:var(--c-field-700);font-weight:600}
.play-list__kind[data-state="failed"]{color:#7a4b00;font-weight:600}
.plans-teaser__addon{margin:0 0 1.5rem 0;color:var(--c-ink-600);font-size:.95rem}
.plans-teaser__addon strong{color:var(--c-ink-900)}
.plans-teaser__cta{margin:0}
@media (min-width:760px){.plan-mini-grid{grid-template-columns:repeat(4,1fr)}}

/* --------------------------------------------------------------------
   Pricing — five-card grid + billing toggle
   -------------------------------------------------------------------- */
.pricing-grid--five{grid-template-columns:repeat(auto-fit,minmax(210px,1fr));max-width:1180px;align-items:stretch}
.price-card--free{background:var(--c-chalk)}
.price-card__feature--off{color:var(--c-ink-400)}
.price-card__save{margin:-.4rem 0 1rem 0;font-size:.78rem;font-weight:700;letter-spacing:.02em;color:var(--c-field-700)}
.pricing-grid.is-monthly .price-card__save{visibility:hidden}
@media (min-width:1024px){.price-card--featured{transform:translateY(-10px)}}
.billing-toggle{display:flex;align-items:center;justify-content:center;gap:.85rem;margin:.5rem auto 0}
.billing-toggle__label{font-family:var(--font-display);font-size:var(--t-eyebrow);letter-spacing:.14em;text-transform:uppercase;color:var(--c-ink-400)}
.billing-toggle__switch{display:inline-flex;background:var(--c-paper);border:1px solid var(--c-line);border-radius:var(--r-pill);padding:3px;gap:2px}
.billing-toggle__opt{margin:0;cursor:pointer}
.billing-toggle__input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.billing-toggle__pill{display:inline-flex;align-items:center;gap:.4rem;padding:.45rem 1rem;border-radius:var(--r-pill);font-weight:600;font-size:.9rem;color:var(--c-ink-600);transition:background 140ms ease,color 140ms ease}
.billing-toggle__input:checked + .billing-toggle__pill{background:var(--c-field-700);color:#fff}
.billing-toggle__save{font-style:normal;font-size:.72rem;font-weight:700;padding:.08rem .4rem;border-radius:var(--r-pill);background:var(--c-endzone);color:var(--c-ink-900)}
.billing-toggle__input:focus-visible + .billing-toggle__pill{outline:3px solid var(--c-endzone-deep);outline-offset:2px}
.pricing__addon{margin:1.75rem auto 0;max-width:40rem;text-align:center;color:var(--c-ink-600);font-size:.95rem}
.pricing__addon strong{color:var(--c-ink-900)}
.pricing__tax-note{margin:1rem auto 0;max-width:40rem;text-align:center;color:var(--c-ink-600);font-size:.85rem}
@media (max-width:759px){.price-card--featured{order:-1}}
@media (min-width:760px){.price-card--featured{order:0}}

/* New-play page: two-column form-left / live-formation-preview-right.
   flex-wrap stacks on narrow widths; the explicit column rule below the
   720px breakpoint guarantees full-width stacking on phones (form first
   so the autofocused name field stays first in tab/visual order). The
   .auth-card margin override is SCOPED to this layout so login/signup
   etc. keep their centered card. */
.new-play-layout {
    display: flex;
    gap: 1.5rem;
    align-items: flex-start;
    flex-wrap: wrap;
}
.new-play-layout > .auth-card {
    margin: 1.5rem 0;
    flex: 1 1 380px;
    min-width: 0;
}
.formation-preview {
    flex: 0 1 300px;
    align-self: stretch;
    position: sticky;
    top: 1rem;
    background: var(--c-paper);
    border: 1px solid var(--c-line);
    border-radius: var(--r-card);
    padding: 1rem;
    box-shadow: var(--shadow-soft);
    margin: 1.5rem 0;
}
.formation-preview__title {
    margin: 0 0 0.75rem;
    font-size: 1rem;
    color: var(--c-ink-600);
}
.formation-preview__svg {
    max-width: 300px;
}
/* "Preview unavailable" fallback: the .play-list__thumbnail box is
   field-green (#2e7d32), so the message needs a light color to read. */
.formation-preview__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 300px;
    color: var(--c-paper);
    font-size: 0.9rem;
    text-align: center;
}
.formation-preview__caption {
    margin: 0.75rem 0 0;
    color: var(--c-ink-600);
    font-size: 0.95rem;
}

@media (max-width: 720px) {
    .new-play-layout { flex-direction: column; }
    .formation-preview {
        flex-basis: auto;
        width: 100%;
        position: static;
    }
}

/* Optional league-rule toggles on the starter form. A wrapped row of checkboxes
   above the free-text box; ticking one appends its sentence there so the coach
   can see what the AI is told. */
.starter-field__rule-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1rem;
    margin: 0 0 0.6rem;
}
.starter-field__rule-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.88rem;
    color: var(--c-ink-900);
    cursor: pointer;
}

/* League-ruleset chooser: which of the four flag codes the AI designs under.
   Shared by BOTH AI entry points — the starter form and the single-play "new
   play with AI" form — so the class names are deliberately page-neutral rather
   than living in either page's ``starter-field__`` / ``auth-field__`` namespace.
   Change them with both surfaces in view.

   Stacked rather than a wrapped row (unlike the rule toggles above): each
   choice carries a second line naming its rulebook, and four two-line cards in
   a flex row wrap into unreadable ragged columns on a phone. */
.ruleset-choices {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin: 0 0 0.6rem;
}
.ruleset-choice {
    display: grid;
    /* The radio sits in column 1 and spans nothing; both text rows live in
       column 2, so the hint aligns under the label rather than under the
       control. */
    grid-template-columns: auto 1fr;
    gap: 0.1rem 0.55rem;
    align-items: baseline;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--c-line);
    border-radius: var(--r-input);
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.ruleset-choice:hover { border-color: var(--c-field-300); }
/* Keyboard focus has to land on the CARD, not just the native radio ring:
   the whole row is the click target, so the visible focus must match it. */
.ruleset-choice:focus-within {
    border-color: var(--c-field-300);
    box-shadow: 0 0 0 3px rgba(63, 181, 107, 0.22);
}
/* Selected state, decorative only — the native radio is what actually
   communicates the choice, so a browser without ``:has()`` support loses a
   tint and nothing else. */
.ruleset-choice:has(input:checked) {
    border-color: var(--c-field-300);
    background: var(--c-field-50);
}
.ruleset-choice input { margin: 0; }
.ruleset-choice__label {
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--c-ink-900);
}
.ruleset-choice__blurb {
    grid-column: 2;
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--c-ink-600);
}

/* Founder-supplied AI disclaimer in the Terms (Section 7). Boxed and tinted so
   it reads as a standing caveat a reader should not skim past, without shouting
   like an error banner. */
.legal-disclaimer {
    margin: 0 0 1rem;
    padding: 0.85rem 1rem;
    border-left: 4px solid var(--c-field-700, #2F6F3E);
    border-radius: 4px;
    background: var(--c-field-50, #F1F7F2);
}

/* SLOT CHIP — a position label wearing the colour the coach chose for it.
   The schedule grid printed positions as plain text, so the colour that ties a
   row to the marker on the field diagram lived only in the drawing.

   ``background`` and ``color`` are set INLINE by the template, not here: they
   are the coach's data, and the ink is computed per background
   (``position_names.readable_ink_for``) because the palette spans both ends —
   #FF7F0E needs black, #1F77B4 needs white, and a fixed choice here would make
   half the chips unreadable. Everything that is not data lives in this rule. */
.slot-chip {
    display: inline-block;
    min-width: 2.1rem;
    padding: 0.12rem 0.42rem;
    border-radius: 0.28rem;
    font-weight: 700;
    font-size: 0.82rem;
    line-height: 1.35;
    text-align: center;
    letter-spacing: 0.01em;
    /* A hairline of the ink itself, so a chip whose colour is close to the page
       background still reads as a chip rather than as floating text. */
    box-shadow: inset 0 0 0 1px currentColor;
}

/* Inline hint under a settings field — used by the schedule label to say what
   an EMPTY box will fall back to, so "leave it blank" reads as a choice rather
   than an omission. */
/* Narrow screens: four columns in ~340px of width is unusable, so the row
   becomes slot + a stack. The colour swatches keep their own line, which is
   what they need anyway (nine of them wrap regardless below ~420px). */
@media (max-width: 720px) {
    .settings-position {
        grid-template-columns: 64px minmax(0, 1fr);
    }
    .settings-position__field--color {
        grid-column: 1 / -1;
    }
}

.settings-position__hint {
    margin: 0.18rem 0 0;
    font-size: 0.72rem;
    line-height: 1.3;
    color: #6b7280;
}

/* SIT-OUTS on the schedule bench. A coach's own DECISION ("Devon rests the
   4th") has to look different from a gap she has not filled yet — in a flat
   list of names the two are indistinguishable, and deciding first is the whole
   point of the control. */
.bench-sit {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    margin: 0 0.2rem 0.15rem 0;
    padding: 0.05rem 0.2rem 0.05rem 0.35rem;
    border-radius: 0.7rem;
    background: #e5e7eb;
    color: #111827;
    font-size: 0.8rem;
    font-weight: 600;
}
.bench-sit__undo {
    border: 0;
    background: transparent;
    padding: 0 0.15rem;
    font-size: 0.9rem;
    line-height: 1;
    color: #6b7280;
    cursor: pointer;
}
.bench-sit__undo:hover,
.bench-sit__undo:focus-visible { color: #b91c1c; }
.bench-sit-picker {
    margin-left: 0.2rem;
    font-size: 0.75rem;
    padding: 0.05rem 0.15rem;
}
/* Print: the picker and the undo buttons are controls, not information. The
   NAMES stay — a printed schedule should still say who is resting. */
@media print {
    .bench-sit-picker,
    .bench-sit__undo { display: none !important; }
}

/* DEFENSIVE grid row headers. The header cell is the naming control: the coach
   looking at the grid is the one who knows what the row is, so she types it
   there rather than in a settings form somewhere else. The number stays
   visible so an unnamed row is still something you can point at.

   The flex lives on an inner DIV, not on the ``<th>``: ``display: flex`` on a
   table cell takes it out of the table formatting context, and the column
   widths stop agreeing with the header row above. */
.defense-row-head {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}
.defense-row-head__num {
    flex: 0 0 auto;
    min-width: 1.1rem;
    font-size: 0.75rem;
    font-weight: 700;
    color: #9ca3af;
    text-align: right;
}
.defense-row-head__input {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    padding: 0.15rem 0.3rem;
    border: 1px solid #d1d5db;
    border-radius: 0.25rem;
    font: inherit;
    font-size: 0.85rem;
    background: #fff;
    color: #111827;
}
.defense-row-head__input::placeholder {
    color: #9ca3af;
    font-style: italic;
    font-weight: 400;
}
/* Print: an empty input is a control, not information — but a NAMED row must
   still print its name, so the border goes and the text stays. */
@media print {
    .defense-row-head__num { color: #111827; }
    .defense-row-head__input {
        border: 0;
        padding: 0;
        background: transparent;
        font-weight: 600;
    }
    .defense-row-head__input::placeholder { color: transparent; }
}

/* The Playing-time tally. Its own class because the obvious-looking
   ``play-list`` is a grid container for the <ul> lists elsewhere, and applying
   it to a <table> silently un-tables it. */
.schedule-tally th,
.schedule-tally td {
    padding: 0.3rem 0.4rem;
    border-bottom: 1px solid var(--c-line);
}
.schedule-tally thead th {
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #6b7280;
}

