/* The YEAR CALENDAR (M-543b) — a whole year of days on one surface, in either of two shapes.
 *
 * Presentation only. The markup is <x-platform::year-calendar> (one server render, whatever the shape) and
 * the behaviour is the `year-calendar` Stimulus controller, which does exactly one thing: swap the modifier
 * class on the root (coding-standards §4 — no inline styles, no markup in JS).
 *
 * ## The whole trick, in one paragraph
 * Both shapes are the SAME cells. Each cell publishes its position as data attributes — `data-column` (1-37,
 * its place in a weekday-aligned month row) and `data-weekday` (1-7, counted from the LOCALE's first day) —
 * and the two blocks of placement rules at the foot of this file put it where the shape wants it. CSS grid's
 * auto-placement supplies the rows for free: an item with a definite column that sits LEFT of the cursor
 * starts a new row (CSS Grid §8.5), which is precisely how a mini-month wraps to its next week.
 *
 * Every colour is a design token, so light -> dark is a token switch and a host theme reaches it too (§12) —
 * including the caller's mark tones, which are a closed set of semantic names (YearCalendarTone) resolved
 * here, never a hex from a caller that no theme re-tuned. */

.platform-year-calendar {
    /* The two cell sizes. The months shape's is FIXED — 37 of them is the width the shape costs, and a cell
       that shrank with the glass would make "a year at a glance" mean something different per device. The
       planner's is fluid (the day cells share their mini-month's width), which is what lets the same shape
       be two columns of ~23px cells on a phone and three of ~40px on a desktop. */
    --platform-year-calendar-cell: 1rem;
    --platform-year-calendar-gap: 1px;
    /* The month-name gutter in the months shape. Sized for the CLDR abbreviation (`led` / `Jan`) plus air. */
    --platform-year-calendar-label: 2.4rem;
}

/* ── The head: year steps + the shape toggle ─────────────────────────────────────────────────────── */

.platform-year-calendar__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--platform-space-sm);
    margin-bottom: var(--platform-space-sm);
}

.platform-year-calendar__nav,
.platform-year-calendar__shapes {
    display: flex;
    align-items: center;
    gap: var(--platform-space-xs);
}

.platform-year-calendar__year {
    font-size: var(--platform-font-size-md);
    /* The year is a label between two links, not a control: it gets the weight, they get the affordance. */
    font-weight: 700;
}

/* The pressed shape is the one in force. `aria-pressed` is the state — this rule only paints what the
   attribute already says, so the two cannot drift and a reader who hears the button gets the same answer. */
.platform-year-calendar__shape[aria-pressed="true"] {
    background: var(--platform-color-accent-surface);
    border-color: var(--platform-color-accent);
    color: var(--platform-color-text);
}

/* ── The scroll box ──────────────────────────────────────────────────────────────────────────────── */

/* THE responsive decision (§12): the grid scrolls inside ITSELF and the page never scrolls sideways — a page
   that scrolls sideways takes its navigation with it. `min-width: 0` matters: this box is routinely a flex/
   grid child (the two-column workspace), where the default `auto` minimum would let 37 columns push the
   whole column wider instead of overflowing here. */
.platform-year-calendar__viewport {
    min-width: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
}

/* Several lanes stack; one lane looks like no rule at all, which is the point (N lanes from day one). */
.platform-year-calendar__lane + .platform-year-calendar__lane {
    margin-top: var(--platform-space-md);
    padding-top: var(--platform-space-md);
    border-top: 1px solid var(--platform-color-border);
}

/* ── A day ───────────────────────────────────────────────────────────────────────────────────────── */

.platform-year-calendar__day {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Square, from whichever axis the shape sizes: the months shape fixes the width, the planner shape lets
       the column decide it. One rule covers both. */
    aspect-ratio: 1;
    border-radius: 2px;
    background: var(--platform-color-surface);
    box-shadow: inset 0 0 0 1px var(--platform-color-border);
    color: var(--platform-color-text);
    font-size: 0.65rem;
    line-height: 1;
    text-decoration: none;
}

/* The two kinds of day off, told apart by more than one shade: the weekend is the muted surface (it recurs,
   it is background), a named non-working day takes the accent tint (it is an event). Neither is the ONLY
   channel — every cell's accessible name says which it is, and names the holiday. */
.platform-year-calendar__day[data-state="weekend"] {
    background: var(--platform-color-surface-muted);
}

.platform-year-calendar__day[data-state="non-working"] {
    background: var(--platform-color-accent-surface);
}

/* Today. After the state rules on purpose (same specificity, later wins): whatever kind of day it is, the
   ring is what says "you are here". */
.platform-year-calendar__day[data-today] {
    box-shadow: inset 0 0 0 2px var(--platform-color-text);
    font-weight: 700;
}

/* A day that leads somewhere behaves like a link and says so under the pointer; a day that leads nowhere is
   a <span role="img"> in the markup and gets neither. */
a.platform-year-calendar__day {
    cursor: pointer;
}

a.platform-year-calendar__day:hover {
    box-shadow: inset 0 0 0 2px var(--platform-color-accent-strong);
}

.platform-year-calendar__day:focus-visible {
    outline: 2px solid var(--platform-color-text);
    outline-offset: 1px;
    /* Above its neighbours, or the outline is clipped by the next cell's background. */
    z-index: 1;
}

/* ── Picking a period (M-543c) ────────────────────────────────────────────────────────────────────
 *
 * Only ever on a calendar the caller opted into (`--selectable`); the read-only overview keeps every rule in
 * this block at arm's length. The classes are handed to the picker controller from Blade as Stimulus classes,
 * so the vocabulary below is never spelled out in JavaScript. */

/* A day is a real <button> in a picker, so the browser's own button dress has to come off — everything that
 * makes a cell a cell is on `.platform-year-calendar__day` above, and Bootstrap's Reboot already inherits the
 * font, so nothing here touches type. */
button.platform-year-calendar__day {
    appearance: none;
    padding: 0;
    border: 0;
    cursor: pointer;
}

/* THE TOUCH DECISION: the grid keeps the gesture. Without this a drag down a mini-month is read as a page
 * scroll and the calendar slides out from under the finger mid-selection. Scoped to the day grids of a
 * SELECTABLE calendar — a read-only year scrolls like any other page, and even here the head, the month names
 * and everything around the calendar still take a scroll, so a phone is never stuck. `user-select` goes with
 * it: a drag across day numbers would otherwise leave a text selection smeared over the year.
 *
 * The trade-off, stated rather than discovered: in the `months` shape the grid is wider than a phone and pans
 * inside its own box, and a finger that starts ON a day now selects instead of panning. What still pans it is
 * everything in that box that is not a day — the weekday ruler above the twelve rows and the month-name gutter
 * beside them, both full-width and both `touch-action: auto`. The mobile default is the `planner` shape, which
 * needs no panning at all. */
.platform-year-calendar--selectable .platform-year-calendar__days {
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
}

/* The range, as ONE range. The wash sits ABOVE the mark bands (which fill the cell) but is translucent, so a
 * day that is both booked and selected still reads as both — colour is added, never replaced. The endpoints
 * take a full accent ring so a range's two ends are distinguishable from the days between them at a glance;
 * a single-day selection is a cell that is both ends, and gets the ring all the same. */
.platform-year-calendar__day--selected::after {
    position: absolute;
    /* Inside the cell's own 1px inset frame, so the day's state (weekend / holiday) still frames the range. */
    inset: 1px;
    border-radius: 1px;
    /* The flat tint first, the translucent wash second: a browser without `color-mix` keeps a legible (if
       opaque) range rather than none at all. Both are tokens, so dark mode re-tunes them with the theme. */
    background: var(--platform-color-accent-surface);
    background: color-mix(in srgb, var(--platform-color-accent) 30%, transparent);
    content: "";
}

/* The two ends of the range, told apart from the days between by a solid ring rather than by more of the same
   colour. On the wash rather than on the cell, so the cell's own rings — the border and today's — survive. */
.platform-year-calendar__day--from::after,
.platform-year-calendar__day--to::after {
    background: var(--platform-color-accent);
    background: color-mix(in srgb, var(--platform-color-accent) 55%, transparent);
    box-shadow: inset 0 0 0 2px var(--platform-color-accent-strong);
}

/* ── The marks ───────────────────────────────────────────────────────────────────────────────────── */

/* The caller's marks sit INSIDE the cell's own edge, so the day's state (weekend / holiday) stays visible as
   a frame around them rather than being painted over. Several marks split the cell into equal bands — the
   same-day rule — and `overflow: hidden` keeps them inside the rounded corner. */
.platform-year-calendar__marks {
    position: absolute;
    inset: 2px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: 1px;
}

.platform-year-calendar__mark {
    flex: 1 1 0;
    /* Never smaller than a hairline: at the band cap this is 1/3 of a 12px cell, and it must stay a stripe
       rather than round away to nothing on a fractional layout. */
    min-height: 1px;
    /* The flat paint, from whichever tone calendar-tones.css resolved. The fallback is the tone a mark takes
       when its caller names none (YearCalendarMark's own default), so a mark is never unpainted. */
    background-color: var(--platform-calendar-tone, var(--platform-color-accent));
}

/* THE TONE AND THE RAMP MOVED TO calendar-tones.css (M-723a). They were declared here while the year calendar
   was the only thing that painted a tone; the timeline paints the same five and shades them on the same ramp,
   and a second copy of "what accent means" is how one surface comes to disagree with another about the colour
   of a holiday. What is left in this file is the year calendar's own geometry. */

/* "…and others": the band that stands for the marks the cell had no room to draw. Hatched OVER its own tone
   rather than replacing it, because a plain band would claim to be one more mark of that tone. The marks it
   covers are all named in the cell's accessible name — this is a visual summary, never the only record. */
.platform-year-calendar__mark--more {
    background-image: repeating-linear-gradient(
        45deg,
        var(--platform-color-text-muted) 0,
        var(--platform-color-text-muted) 2px,
        transparent 2px,
        transparent 4px
    );
}

/* ── The weekday rulers ──────────────────────────────────────────────────────────────────────────── */

.platform-year-calendar__weekday {
    overflow: hidden;
    color: var(--platform-color-text-muted);
    font-size: 0.55rem;
    line-height: 1.4;
    text-align: center;
}

.platform-year-calendar__month-name {
    color: var(--platform-color-text-muted);
    font-size: var(--platform-font-size-xs);
    white-space: nowrap;
}

/* ══ SHAPE 1: months ═════════════════════════════════════════════════════════════════════════════════
 * Twelve rows, one per month, every row on the same 37-column grid — which is what makes the weekends line
 * up into vertical stripes and a period read left-to-right along a row. */

.platform-year-calendar--months .platform-year-calendar__months {
    display: flex;
    flex-direction: column;
    gap: var(--platform-year-calendar-gap);
}

/* The ruler row and every month row share one two-column template — name gutter, then days — so the ruler
   sits exactly above the columns it names. */
.platform-year-calendar--months .platform-year-calendar__strip,
.platform-year-calendar--months .platform-year-calendar__month {
    display: grid;
    grid-template-columns: var(--platform-year-calendar-label) auto;
    justify-content: start;
    align-items: center;
    gap: 0 var(--platform-space-xs);
}

.platform-year-calendar--months .platform-year-calendar__strip-days {
    grid-column: 2;
}

.platform-year-calendar--months .platform-year-calendar__strip-days,
.platform-year-calendar--months .platform-year-calendar__days {
    display: grid;
    grid-template-columns: repeat(37, var(--platform-year-calendar-cell));
    gap: var(--platform-year-calendar-gap);
}

.platform-year-calendar--months .platform-year-calendar__month-name {
    text-align: right;
}

/* The long month name and the per-month seven-day ruler belong to the planner shape; here the row label is
   the abbreviation and the ruler is the 37-column strip above all twelve rows. */
.platform-year-calendar--months .platform-year-calendar__month-name--long,
.platform-year-calendar--months .platform-year-calendar__weekdays {
    display: none;
}

/* A 16px cell cannot carry a two-digit number legibly, and it does not have to: the date is in the cell's
   accessible name and its tooltip. */
.platform-year-calendar--months .platform-year-calendar__num {
    display: none;
}

.platform-year-calendar--months .platform-year-calendar__marks {
    inset: 1px;
}

/* ══ SHAPE 2: planner ════════════════════════════════════════════════════════════════════════════════
 * Twelve mini-months in a wall-planner grid. MOBILE FIRST, and this is the shape a phone should open in:
 * seven columns fit any screen, so nothing scrolls sideways at all. */

.platform-year-calendar--planner .platform-year-calendar__strip {
    display: none;
}

.platform-year-calendar--planner .platform-year-calendar__months {
    display: grid;
    /* Base = phone: as many mini-months as fit, and the cells grow to fill whichever it is. Measured, not
       guessed: at 390px the calendar's inner box is 317px, so a 9rem floor with an 8px gutter gives TWO
       columns (2x144 + 8 = 296) and the year is a screen and a half. A 10rem floor gave one column and a
       3 430px page — a year you scroll through four times is not a year at a glance. */
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
    gap: var(--platform-space-sm);
}

.platform-year-calendar--planner .platform-year-calendar__month-name {
    display: block;
    margin-bottom: 0.15rem;
    color: var(--platform-color-text);
    font-size: var(--platform-font-size-sm);
    font-weight: 600;
    text-align: center;
}

.platform-year-calendar--planner .platform-year-calendar__month-name--short {
    display: none;
}

.platform-year-calendar--planner .platform-year-calendar__weekdays,
.platform-year-calendar--planner .platform-year-calendar__days {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--platform-year-calendar-gap);
}

@media (min-width: 48em) {
    /* The 3x4 wall planner, from tablet up. Capped rather than free `1fr`: on a full-width page three
       unbounded columns would blow a mini-month up to half a hand span, which is a poster, not a calendar. */
    .platform-year-calendar--planner .platform-year-calendar__months {
        grid-template-columns: repeat(3, minmax(0, 18rem));
        justify-content: start;
        gap: var(--platform-space-md);
    }
}

/* ══ Placement ═══════════════════════════════════════════════════════════════════════════════════════
 * The 44 rules the whole one-DOM-two-shapes idea rests on. Written once, here; nothing computes a style
 * anywhere else, and no cell carries one.
 *
 * WHY ALL 44, WHEN 19 WOULD DRAW THE SAME PICTURE. Strictly, only each month's FIRST cell needs a definite
 * column: the other thirty auto-place after it, because their columns ascend and grid's cursor follows
 * (CSS Grid §8.5). That would be twelve month-openers (at most seven distinct columns) plus the planner's
 * seven — and it would make every other cell's position an INFERENCE from its neighbour rather than a fact
 * about itself.
 *
 * The full set is kept deliberately, and the choice is a robustness one, not a stylistic one:
 *   - a cell placed by its own `data-column` is right even if the cell before it is missing, reordered, or
 *     filtered out — which is exactly the sort of thing the selection card (M-543c) may end up doing;
 *   - it holds if a future shape ever renders a partial month, or a lane starts mid-year;
 *   - the guard in YearCalendarComponentTest can then check the ONE thing that must be true — that column N
 *     lands in grid column N — for every column the model can emit, rather than for a sample.
 * The cost is ~30 lines of the most boring CSS in the repo. A stylesheet that is boring beats one that is
 * minimal and load-bearing in a way only its author can see.
 *
 * Both blocks are generated shapes, one rule per line: if the model's column count ever changes, the test
 * below goes red rather than a December day quietly landing in the row above. */

/* The months shape: 37 columns, one rule each — 37 because a month can open on the 7th day of the week and
   run 31 days (YearCalendarViewBuilder::COLUMNS). */
.platform-year-calendar--months .platform-year-calendar__day[data-column="1"] { grid-column: 1; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="2"] { grid-column: 2; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="3"] { grid-column: 3; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="4"] { grid-column: 4; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="5"] { grid-column: 5; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="6"] { grid-column: 6; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="7"] { grid-column: 7; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="8"] { grid-column: 8; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="9"] { grid-column: 9; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="10"] { grid-column: 10; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="11"] { grid-column: 11; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="12"] { grid-column: 12; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="13"] { grid-column: 13; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="14"] { grid-column: 14; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="15"] { grid-column: 15; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="16"] { grid-column: 16; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="17"] { grid-column: 17; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="18"] { grid-column: 18; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="19"] { grid-column: 19; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="20"] { grid-column: 20; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="21"] { grid-column: 21; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="22"] { grid-column: 22; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="23"] { grid-column: 23; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="24"] { grid-column: 24; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="25"] { grid-column: 25; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="26"] { grid-column: 26; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="27"] { grid-column: 27; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="28"] { grid-column: 28; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="29"] { grid-column: 29; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="30"] { grid-column: 30; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="31"] { grid-column: 31; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="32"] { grid-column: 32; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="33"] { grid-column: 33; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="34"] { grid-column: 34; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="35"] { grid-column: 35; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="36"] { grid-column: 36; }
.platform-year-calendar--months .platform-year-calendar__day[data-column="37"] { grid-column: 37; }

/* The planner shape: seven columns, counted from the locale's own first day — which is why these are
   `data-weekday` values and not day names. The ROWS are grid auto-placement's, not ours. */
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="1"] { grid-column: 1; }
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="2"] { grid-column: 2; }
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="3"] { grid-column: 3; }
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="4"] { grid-column: 4; }
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="5"] { grid-column: 5; }
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="6"] { grid-column: 6; }
.platform-year-calendar--planner .platform-year-calendar__day[data-weekday="7"] { grid-column: 7; }

/* ── The legend (M-716) ──────────────────────────────────────────────────────────────────────────────
 * The key to the colours, at the bottom of the card, sharing one row until it runs out of width. Every swatch
 * in it is a real `.platform-year-calendar__day` (with a real `__mark` inside it where the entry stands for
 * one), so every colour above is already declared and NONE of it is re-declared here — which is the whole
 * reason the swatch is built out of the grid's own classes rather than out of a copy of their tokens.
 *
 * What this section adds is therefore only what a cell cannot bring with it: a SIZE. In the grid a day sizes
 * from its column (`aspect-ratio: 1` does the rest); standing alone in a legend it has no column, so it would
 * be zero wide. `--platform-year-calendar-cell` is the months shape's own cell — the same square, at the size
 * the component already calls a day. */

.platform-year-calendar__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--platform-space-xs, 0.25rem) var(--platform-space-md, 1rem);
    margin: var(--platform-space-md, 1rem) 0 0;
    padding: var(--platform-space-sm, 0.5rem) 0 0;
    border-top: 1px solid var(--platform-color-border);
    list-style: none;
    color: var(--platform-color-text-muted);
    font-size: var(--platform-font-size-sm);
}

.platform-year-calendar__key {
    display: flex;
    align-items: center;
    gap: var(--platform-space-xs, 0.25rem);
}

/* The swatch's size, and nothing else about it. Scoped to the legend so a day in the GRID is untouched: there
   the column decides, and it must go on deciding. */
.platform-year-calendar__legend .platform-year-calendar__day {
    flex: none;
    width: var(--platform-year-calendar-cell);
}

/* The page's own line about this calendar, under the legend and inside the card. */
.platform-year-calendar__hint {
    margin: var(--platform-space-sm, 0.5rem) 0 0;
    color: var(--platform-color-text-muted);
    font-size: var(--platform-font-size-sm);
}
