/*
 * SPDX-FileCopyrightText: 2026-present TeamCalendar
 * SPDX-License-Identifier: LicenseRef-Proprietary
 *
 * What renders INSIDE the main region: the leagues, the success and edit
 * states, and the miss.
 *
 * The tokens this file reads, the reset, and the four regions themselves moved
 * to layout.css with PRD 170's shell (build item 3) — a custom property
 * resolves where it is used rather than where it is declared, so the split
 * costs this file nothing and lets build item 8's static pages link the chrome
 * without linking a picker they do not have.
 *
 * Served from /assets, which Program.cs caches for an hour with revalidation
 * and CalendarFeedEndpoints reserves against the feed catch-all. The filename
 * is conventional rather than fingerprinted — the same trade the team marks
 * make, for the same reason: a rebuild reuses the name, so an immutable
 * response would pin a retired stylesheet in caches with no purge step.
 */

.picker-status {
    margin: 0;
    color: var(--ink-soft);
}

/* ── The picker itself (build item 2) ─────────────────────────────────────── */

.leagues {
    list-style: none;
    margin: 0;
    padding: 0;
}

.league details {
    border-bottom: 1px solid var(--rule);
}

/* The disclosure triangle is the affordance, so it stays; what is removed is
   Safari's default list-item marker box, which puts it in a different place
   from every other browser. */
.league-summary {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.75rem 0;
    cursor: pointer;
    font-weight: 600;
}

.league-summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.league-picked {
    color: var(--accent);
    font-size: 0.8125rem;
    font-weight: 500;
}

.league-body {
    padding-bottom: var(--step);
}

/* ── The conference grid (build item 5) ───────────────────────────────────── */

/* Headings are `<h3>`s under the panel's `<summary>`, so the grid reads as the
   outline it looks like. A league whose teams carry no conference has exactly
   one of them, labelled "All teams" — which is why this spacing has to look
   deliberate with a single heading as well as with three. */
.conference + .conference {
    margin-top: var(--step);
}

.conference-heading {
    margin: 0 0 0.5rem;
    color: var(--ink-soft);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.conference[hidden] {
    display: none;
}

.teams {
    list-style: none;
    margin: 0 0 var(--step);
    padding: 0;
    /* Rosters are tens of rows, so they get columns rather than one long
       scroll; auto-fill collapses to a single column on a phone with no
       breakpoint to maintain. */
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.125rem var(--step);
}

/* A row the search box filtered out. It stays in the DOM and stays checked —
   a hidden checkbox still contributes to the form — so narrowing the grid never
   drops a club the visitor had already picked. */
.team-cell[hidden] {
    display: none;
}

.team,
.season {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.5rem;
    border-radius: var(--radius);
    cursor: pointer;
}

.season:hover {
    background: var(--panel);
}

.season:focus-within {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* The selection affordance is a REAL checkbox, hidden from sight and from
   nowhere else. `display: none` and `visibility: hidden` would both take it out
   of the focus order and out of the accessibility tree, which is the whole
   thing the native control was kept for — so it is clipped to a pixel instead
   and the card beside it carries every visible state. */
.team-choice {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* The card. It is the border, the mark and the name — a selection state a mouse
   user can read at a glance and a target the whole row is. */
.team-card {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
    padding: 0.375rem 0.5rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--page);
}

.team:hover .team-card {
    background: var(--panel);
}

/* Not colour alone: the card gains a second border's worth of weight as well as
   the accent, so the picked state survives a display that cannot separate the
   two hues. The checkbox itself still announces the state to a screen reader. */
.team-choice:checked + .team-card {
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
}

/* Focus follows the input and is drawn on the card, because the input is a
   pixel and an outline around it would be invisible. */
.team-choice:focus-visible + .team-card {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.team-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Marks arrive as SVG at whatever intrinsic size the artwork carries, and the
   set is not uniform — contain keeps a wide wordmark and a round crest on the
   same baseline without cropping either. */
.team-mark {
    width: 28px;
    height: 28px;
    object-fit: contain;
    flex: none;
}

/* ── The search box (build item 5) ────────────────────────────────────────── */

/* Above the leagues rather than inside one: it narrows every panel that is
   open, and a control that sat inside a panel would read as filtering that
   league alone. */
.picker-search {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: var(--step);
}

.search-label {
    color: var(--ink-soft);
    font-size: 0.875rem;
    white-space: nowrap;
}

.search-input {
    flex: 1 1 16rem;
    min-width: 0;
    max-width: 22rem;
    padding: 0.375rem 0.625rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--panel);
    color: var(--ink);
    font: inherit;
}

.search-input:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -1px;
}

.seasons {
    margin: 0;
    padding: var(--step);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--panel);
}

.seasons legend {
    padding-inline: 0.375rem;
    font-weight: 600;
}

.seasons-note {
    margin: 0 0 0.5rem;
    color: var(--ink-soft);
    font-size: 0.875rem;
}

.seasons ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* A locked season is a season whose league has no team picked yet. It stays
   visible — hiding it would make the note above it describe nothing. */
.seasons input:disabled + span {
    color: var(--ink-soft);
}

/* The footer, with the button gone (build item 5). What is left is what the
   button used to say without words: how many teams are picked, and — when a
   toggle was refused — why. It stays sticky because a toggle at the foot of a
   thirty-two-club roster is a save, and the acknowledgement has to be where the
   visitor is looking rather than at the top of the page. */
.picker-actions {
    position: sticky;
    bottom: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem var(--step);
    margin-top: calc(var(--step) * 1.5);
    padding: var(--step) 0;
    border-top: 1px solid var(--rule);
    background: var(--page);
}

.picker-tally {
    margin: 0;
    color: var(--ink-soft);
}

/* The way on to the calendar step, and phone-only: above the breakpoint the
   panel is already beside the grid, so there is nowhere for this to go. */
.picker-onward {
    display: none;
    margin-left: auto;
    min-height: 2.75rem;
    padding: 0 1.25rem;
    border: 0;
    border-radius: var(--radius);
    background: var(--accent);
    color: var(--panel);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.picker-onward:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.picker-refusal {
    margin: 0;
    /* Not colour alone: the refusal is announced (role="alert") and reads as a
       refusal in its words, so a visitor who cannot distinguish the hue still
       gets all of it. */
    font-weight: 600;
}

.picker-refusal[hidden] {
    display: none;
}

.feed-link {
    color: var(--accent);
}

/* ── The subscribe panel, below the grid (build items 3 and 5) ────────────── */

/* The panel sits BELOW the form rather than over it: a toggle is the save, so
   the grid stays on screen and a visitor can keep adding and removing after
   they have their link. This is the box; what goes in it is the success state
   below, rendered on every visit that holds a `cid` (build item 6). */
.subscribe-panel {
    display: block;
    margin-top: calc(var(--step) * 2);
    padding-top: var(--step);
    border-top: 1px solid var(--rule);
}

.subscribe-panel[hidden] {
    display: none;
}

/* ── The third pane (PRD 170 as amended 2026-09-16) ───────────────────────── */

/* §4b put this panel "in the main region, below the grid". On a desktop it now
   sits BESIDE the grid instead, which is the same claim about the same region
   with room the phone does not have: the grid stays on screen, the visitor can
   still add and remove, and the link they came for is no longer underneath a
   thirty-two-row roster.
   
   `auto` and not a fixed second track: the panel renders only once a `cid`
   exists, and until then it is `[hidden]` and the track collapses to nothing
   rather than reserving a column-shaped hole beside a full-width grid. */
#picker {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: calc(var(--step) * 2);
    align-items: start;
    /* The reading column keeps `--measure`; the panel gets its own width on top,
       rather than the two of them sharing one line length neither wants. */
    max-width: calc(var(--measure) + 24rem);
}

.picker-form {
    min-width: 0;
}

.subscribe-panel {
    width: 22rem;
    /* It is the thing the visitor came for, so it stays with them while they
       scroll the roster beside it. */
    position: sticky;
    top: calc(var(--header-height) + var(--step));
    /* And it scrolls ITSELF, which the canvas drew (`overflow-y: auto` on a
       fixed-width column) and the build left out.
       
       Without it this is a trap rather than a nicety: a sticky box taller than
       the viewport pins at `top` and the page scrolls PAST it, so everything
       below the fold inside the column is unreachable at any scroll position.
       A roster plus the fixtures clears a laptop viewport easily, which put the
       tail of *Next up* somewhere no one could read it. */
    max-height: calc(100vh - var(--header-height) - var(--step) * 2);
    overflow-y: auto;
    /* Room for the scrollbar the line above can summon, so a gutter appearing
       does not reflow the rows it appears beside. */
    scrollbar-gutter: stable;
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

/* One league's teams at a time, which is what the rail is for. Every panel is
   still IN the document and every checked box still reaches the write — closing
   is not unrendering, and `A_league_switch_keeps_every_club_already_picked`
   fails the moment that stops being true.
   
   Guarded by `:has` so that `/` — no league selected, nothing open — still shows
   all five summaries as a list to choose from. */
.leagues:has(details[open]) .league details:not([open]) {
    display: none;
}

/* ── The success and edit states (build item 3) ───────────────────────────── */

/* The return path's own note. It sits above the leagues because the thing it
   answers — "will saving change my subscribe link?" — is asked before anything
   is picked, not after. */
.editing-note {
    margin: 0 0 var(--step);
    padding: 0.75rem var(--step);
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius) var(--radius) 0;
    background: var(--panel);
    color: var(--ink-soft);
}

.success-heading {
    margin: 0 0 var(--step);
    font-size: 1.375rem;
    letter-spacing: -0.02em;
}

/* The live line, directly under the heading and above everything a write does
   not touch. Full ink and a touch larger than the lead it replaced, because it
   is the sentence that answers "did my pick land?" — the one thing on this
   panel a visitor comes BACK to read. */
.success-contents {
    margin: 0 0 var(--step);
    color: var(--ink);
    font-size: 0.9375rem;
}

/* The two live regions under the address. Each is a wrapper `markup.js` keeps
   across a patch, so the spacing has to live on the wrapper rather than on the
   heading inside it — an empty region collapses to nothing instead of leaving a
   heading's top margin behind. */
.success-section:not(:empty) {
    margin-top: calc(var(--step) * 1.5);
}

/* Drawn as a kicker on the canvas and shipped as a heading, which made it
   louder than the address it sits under and left no room for the count that
   was the point of it. This is `.conference-heading`'s vocabulary exactly —
   the same size, weight, tracking and ink — because the picker already has a
   way of labelling a list and a second one would be a second system. */
.success-kicker {
    margin: 0 0 0.5rem;
    color: var(--ink-soft);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.subscribe {
    padding: var(--step);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--panel);
}

.subscribe-lead {
    margin: 0 0 var(--step);
    color: var(--ink-soft);
}

/* The calendar-app affordances (build item 6). A row of three, wrapping rather
   than scrolling — three entries fit a phone at this size, and a row that
   scrolled sideways would hide the third one on the width where it matters
   most. */
.calendar-apps {
    list-style: none;
    margin: 0 0 var(--step);
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.calendar-app {
    flex: 1 1 7rem;
}

/* The whole tile is the target, not the word inside it: these are pressed on a
   phone, and a text-sized hit area is the difference between one tap and three.
   `height: 100%` is what makes the three equal — the row stretches every item,
   and without it the entry carrying no mark draws a shorter box inside a
   full-height cell, which reads as a rendering fault rather than a choice
   (iPhone carries none deliberately — see `subscribe.js`). `justify-content`
   then centres its name against the marks beside it. */
.calendar-app-link {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    padding: 0.75rem 0.5rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--page);
    color: var(--ink);
    font-weight: 600;
    text-decoration: none;
}

.calendar-app-link:hover {
    border-color: var(--accent);
}

.calendar-app-mark {
    display: block;
    width: 2rem;
    height: 2rem;
}

.calendar-app-name {
    font-size: 0.9375rem;
}

.feeds {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.5rem;
}

.feed {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* The address and its controls travel together, so a wrap moves the group and
   never strands `Copy` on a line of its own beneath a full-width input — which
   is what a phone did when the three were siblings of the label. */
.feed-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    flex: 1 1 18rem;
}

.feed-url {
    flex: 1 1 12rem;
    min-width: 0;
}

.feed-label {
    flex: 0 0 9rem;
    color: var(--ink-soft);
    font-size: 0.875rem;
}

/* The two minority addresses, folded away. 7,454 distinct calendars fetched
   `/{slug}` in the measured week and nine fetched a variant — so these are one
   tap for the 0.12% and no height for everyone else. Restored by PRD 180 and
   reachable here; the disclosure is about weight, not availability. */
.feed-variants {
    margin-top: var(--step);
}

.feed-variants-summary {
    color: var(--ink-soft);
    cursor: pointer;
    font-size: 0.875rem;
    padding: 0.25rem 0;
}

.feed-variants[open] .feed-variants-summary {
    margin-bottom: 0.5rem;
}

.feed-primary .feed-label {
    color: var(--ink);
    font-weight: 600;
}

.feed-subscribe {
    padding: 0.375rem 0.875rem;
    border-radius: var(--radius);
    background: var(--accent);
    color: var(--page);
    font-weight: 600;
    text-decoration: none;
}

.feed-primary .feed-subscribe {
    padding: 0.5rem 1.125rem;
}

/* Readonly, not disabled: a disabled field cannot be focused, and focusing it
   is how a visitor with a keyboard selects the address to copy. */
.feed-url {
    flex: 1 1 18rem;
    min-width: 0;
    padding: 0.375rem 0.5rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--page);
    color: var(--ink);
    font: inherit;
    font-size: 0.8125rem;
}

.feed-copy {
    padding: 0.375rem 0.75rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--page);
    color: var(--ink);
    font: inherit;
    cursor: pointer;
}

.subscribe-status {
    margin: 0.5rem 0 0;
    min-height: 1.5rem;
    color: var(--ink-soft);
    font-size: 0.875rem;
}

/* The success state's team list is a summary, not a control: no checkbox, no
   hover target, and it reuses the mark sizing so a club looks the same on both
   sides of the create. */
.success .teams {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 0.25rem var(--step);
}

.success .team {
    cursor: default;
}

.success .team:hover {
    background: none;
}

.fixtures {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.25rem;
}

.fixture {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    padding: 0.375rem 0;
    border-bottom: 1px solid var(--rule);
}

.fixture-when {
    flex: 0 0 12rem;
    color: var(--ink-soft);
    font-variant-numeric: tabular-nums;
}

/* The games past the third. The same treatment as `.feed-variants` one region
   up, and for the same reason — a disclosure here is about WEIGHT, not
   availability: ten fixtures is the heaviest thing on this panel and the
   visitor came for the address above it. */
.fixtures-rest {
    margin-top: 0.5rem;
}

.fixtures-rest-summary {
    padding: 0.25rem 0;
    color: var(--ink-soft);
    cursor: pointer;
    font-size: 0.875rem;
}

.fixtures-rest[open] .fixtures-rest-summary {
    margin-bottom: 0.5rem;
}

.success-edit {
    margin: calc(var(--step) * 1.5) 0 0;
    color: var(--ink-soft);
    font-size: 0.875rem;
}

/* ── The uniform miss (build item 4) ──────────────────────────────────────── */

/* Deliberately plain. This is what a visitor who followed a stale link out of
   their calendar app lands on, and it is the one state where the page has
   nothing to offer them but the truth and a way onward — so it gets no panel,
   no accent bar and nothing that reads as an interface waiting to be used. */
.miss {
    padding: calc(var(--step) * 2) 0;
}

.miss-heading {
    margin: 0 0 0.5rem;
    font-size: 1.375rem;
    letter-spacing: -0.02em;
}

/* The legacy sentence, verbatim. It reads as machine wording because it IS the
   feed's wording — the heading above carries the human half, so uniformity with
   the feed costs the visitor nothing. */
.miss-body {
    margin: 0 0 var(--step);
    color: var(--ink-soft);
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
    font-size: 0.9375rem;
    overflow-wrap: anywhere;
}

.miss-onward {
    margin: 0;
}


/* ── Phone ─────────────────────────────────────────────────────────────────────
   The same 40rem `layout.css` uses and `rail.js#PHONE` spells, held together by
   `mobile.test.mjs` — two stylesheets disagreeing about where a phone starts is
   a seam that shows as a rail collapsing at one width and a panel reflowing at
   another, which reads as a bug in neither.

   This file had NO media query at all until 2026-09-16 (issue 0052): the panel
   was desktop flex with fixed bases, and a phone got whatever those bases
   happened to produce — calendar tiles wrapping 2+1, every feed row breaking
   across three lines. */
@media (max-width: 40rem), (max-height: 30rem) {
    /* Three-up and staying three-up. The tiles are the RECOMMENDED path — a
       visitor who knows their app never reads an address at all — so they are
       the last thing that should wrap raggedly. An explicit track count rather
       than a smaller basis, because a basis only hints. */
    .calendar-apps {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
    }

    .calendar-app {
        flex: none;
    }

    /* The label takes its own line, where there is room to read it. A 9rem fixed
       basis on a ~300px row was leaving too little beside it for anything else. */
    .feed-label,
    .feed-actions {
        flex: 1 1 100%;
    }

    /* The address keeps the row it is on and the two controls sit beside it,
       rather than the input taking the full width and pushing them below. */
    .feed-url {
        flex: 1 1 8rem;
    }
}

/* ── One region at a time, on a phone (PRD 170 as amended 2026-09-16) ─────── */

/* The same breakpoint as everywhere else — `rail.js#PHONE`, `layout.css`, and
   the block above — because one breakpoint written in four places is a
   duplication a test closes, not one a comment can. */
@media (max-width: 40rem), (max-height: 30rem) {
    /* The panes stop being panes. `#picker` is one column and the two children
       take turns, which is what `body[data-step]` decides.
       
       Addressed by ID rather than by `.site-main`, and that is not a preference:
       the grid rule above is `#picker`, so a step rule written against the class
       loses to it on specificity and the region stays on screen at every step.
       Measured, the first time this was built. */
    #picker {
        display: block;
        max-width: none;
    }

    body[data-step="1"] #picker {
        display: none;
    }

    .subscribe-panel {
        width: auto;
        position: static;
        /* Step 3 is the whole screen here, so the panel scrolls with the
           document. The desktop column's own scroller would otherwise put a
           second scrollbar inside the only thing on the page. */
        max-height: none;
        overflow-y: visible;
    }

    body[data-step="2"] .subscribe-panel {
        display: none;
    }

    body[data-step="3"] .picker-form {
        display: none;
    }

    /* The grid becomes a ruled list, and that is most of why the phone page
       stopped feeling dense: thirty-two bordered cards in a single column read
       as thirty-two objects, where the same names on ruled rows read as one
       list. The card keeps its border above this breakpoint, where it sits in a
       three-up grid and needs an edge of its own. */
    /* The columns are NOT forced to one. `auto-fill` with the same 15rem track
       the desktop grid uses resolves to one column on a 390px portrait screen
       and to three on an 844px landscape one — which is the whole of what a
       rotated phone needs, without a second breakpoint to keep in step with the
       first.
       
       It matters more here than it looks. A landscape phone is 390px TALL, and
       the header, the step bar, the search row and the tally bar take 244 of
       those: a single column left room for one team. The screen has width it was
       not being asked for.
       
       The row gap stays zero so the rules meet, and the column gap is the site's
       own step so two columns do not butt together. */
    .teams {
        gap: 0 var(--step);
    }

    .team {
        padding: 0;
    }

    /* Two more lines of the same budget: the search box's gap to the roster, and
       the disclosure that names the league. Neither is load-bearing at this size
       -- the step bar already says which step this is, and the league name is one
       line, not a heading with room around it. */
    .picker-search {
        margin-bottom: 0.75rem;
    }

    .league-summary {
        padding: 0.5rem 0;
    }

    .team-card {
        gap: 0.75rem;
        padding: 0.75rem 0.25rem;
        border: 0;
        border-bottom: 1px solid var(--rule);
        border-radius: 0;
        background: none;
        /* The 44px floor: a roster is a list of thumb targets. */
        min-height: 2.75rem;
    }

    .team:hover .team-card {
        background: none;
    }

    /* With the border gone, the picked state needs somewhere else to live — so
       the row grows the checkbox the visually-hidden input has always been.
       A pseudo-element rather than markup: the input is still the control, still
       focusable and still announced, and nothing here is reachable by a screen
       reader that would read the state twice. */
    .team-card::after {
        content: "";
        flex: none;
        margin-left: auto;
        width: 1.375rem;
        height: 1.375rem;
        border: 1.5px solid var(--ink-soft);
        border-radius: 0.3125rem;
    }

    .team-choice:checked + .team-card {
        box-shadow: none;
    }

    .team-choice:checked + .team-card::after {
        border-color: var(--accent);
        background: var(--accent) no-repeat center / 0.75rem 0.75rem
            url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5l5.5 5.5L20 6.5'/%3E%3C/svg%3E");
    }

    /* The tally and the way onward, on one line at the foot of the roster. */
    .picker-onward {
        display: inline-flex;
        align-items: center;
    }
}
