/* Lilai: Shape Calendar on the Bauhaus kit.
   /bauhaus/tokens.css (copied from ~/code/bauhaus, commit in /bauhaus/KIT_COMMIT) loads first
   and owns the palette, both themes, strokes, radii and Jost. This file only names lilai's
   additions in terms of those tokens. Each calendar is one primary shape; primaries live only
   inside shapes. See DESIGN.md. */

:root {
    /* Lilai names for kit tokens. */
    --ink-2: var(--ink-muted);
    --hair: var(--line);
    --wash: var(--stone);
    --rule: var(--stroke-2);

    /* Lilai additions: a fainter ink for ticks and captions, the drained past outline, the scrim. */
    --ink-3: #62625c;
    --past: #a9a9a2;
    --scrim: rgba(22, 22, 22, 0.4);
    /* Lilai's own link colour, an azure kept apart from the kit's ultramarine, which in
       light mode is the first calendar's circle. Outbound links only; focus stays the kit's. */
    --link: #0b57d0;

    /* The lifted page: a grey ground under raised cards (dark keeps paper, so cards sit lighter). */
    --ground: var(--fill);
    /* The date rail's green: the selected day and the agenda accent. Owner's choice, 2026-10-22. */
    --rail-sel: #1f5c43;
    --on-rail-sel: #fafaf7;
    --rail-accent: #2f7d58;

    /* Jost (from the kit) for headings, numerals and labels; reading text keeps the device's
       own UI font, which stays legible at 14-16px where Jost's small x-height does not. */
    --font-display: Jost, Futura, 'PingFang TC', 'Noto Sans TC', 'Microsoft JhengHei', system-ui, sans-serif;
    --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang TC', 'Noto Sans TC', 'Microsoft JhengHei', sans-serif;
    --meta: 14px;
    --ease: cubic-bezier(0.16, 1, 0.3, 1);

    --s1: 4px;
    --s2: 8px;
    --s3: 12px;
    --s4: 16px;
    --s5: 24px;
    --s6: 32px;
    --s7: 48px;
    --s8: 64px;

    --gutter: 16px;
    --page: 1180px;

    color-scheme: light;
    accent-color: var(--ink);
    scrollbar-color: var(--ink) transparent;
}

/* Dark: the kit swaps the palette in tokens.css. These two blocks hold lilai's additions and
   must carry the same values (one follows the device, one is the footer's forced Dark). */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --ink-3: #8f9095;
        --past: #55565b;
        --scrim: rgba(0, 0, 0, 0.4);
        --link: #8ab4f8;
        --ground: var(--paper);
        --rail-sel: #2f7d58;
        --on-rail-sel: #ffffff;
        --rail-accent: #5cbf8c;
        color-scheme: dark;
    }
    :root:not([data-theme="light"]) .select {
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f2f2ee' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    }
}

:root[data-theme="dark"] {
    --ink-3: #8f9095;
    --past: #55565b;
    --scrim: rgba(0, 0, 0, 0.4);
    --link: #8ab4f8;
    --ground: var(--paper);
    --rail-sel: #2f7d58;
    --on-rail-sel: #ffffff;
    --rail-accent: #5cbf8c;
    color-scheme: dark;
}
:root[data-theme="dark"] .select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f2f2ee' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* The kit's button and label styles: sentence-case Jost, semibold. */
.btn {
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 600;
}
/* The same size as the field's text, so the label and its value read as one line of type. */
.field label {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 600;
    color: var(--ink);
}

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

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--ground);
    color: var(--ink);
    font-family: var(--font);
    font-size: 16px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    caret-color: var(--ink);
}

::selection { background: var(--yellow); color: var(--ink); }

a {
    color: var(--ink);
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
    outline: var(--stroke-2) solid var(--focus);
    outline-offset: 2px;
}

h1, h2, h3, p { margin: 0; }

/* Display type: headings and the numerals DESIGN.md calls Numeral, on every page. */
h1, h2, h3, .wordmark-name, .event-day, .balance-amount, .bd-day { font-family: var(--font-display); }

button { font: inherit; color: inherit; }

[hidden] { display: none !important; }

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ---------- Shapes ---------- */

.shape-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

.tone-blue { --tone: var(--blue); }
.tone-red { --tone: var(--red); }
.tone-yellow { --tone: var(--yellow); }
.tone-ink { --tone: var(--ink); }

.shape {
    display: block;
    width: 1em;
    height: 1em;
    overflow: visible;
    fill: var(--tone, var(--ink));
    stroke: var(--ink);
    stroke-width: 1.5px;
    stroke-linejoin: miter;
}

.s-circle { --tone: var(--blue); }
.s-square { --tone: var(--red); }
.s-triangle { --tone: var(--yellow); }
[class*="tone-"] .shape { fill: var(--tone); }

@keyframes shape-grow {
    from { transform: scale(0); }
    to { transform: scale(1); }
}

@keyframes shape-step {
    from { transform: scale(0.6); }
    to { transform: scale(1); }
}

@keyframes name-print {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ---------- Masthead ---------- */

.masthead {
    display: flex;
    align-items: center;
    gap: var(--s4);
    max-width: var(--page);
    margin: 0 auto;
    padding: var(--s3) var(--gutter);
}

.wordmark {
    display: inline-flex;
    align-items: center;
    gap: var(--s3);
    margin-right: auto;
    text-decoration: none;
    min-height: 44px;
}

.wordmark-mark {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 15px;
}

.wordmark-name {
    font-size: 26px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.02em;
}

.app-header-links {
    display: flex;
    align-items: center;
    gap: var(--s4);
}

.app-header-links a {
    font-size: 15px;
    font-weight: 500;
    text-decoration: none;
    padding: var(--s3) 0;
}
.app-header-links a:hover { text-decoration: underline; }

.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    background: none;
    border-radius: var(--radius-full);
    cursor: pointer;
}

.icon-btn svg {
    width: 22px;
    height: 22px;
    fill: none;
    stroke: var(--ink);
    stroke-width: 1.5px;
    stroke-linecap: square;
}

.icon-btn:hover { background: var(--wash); }

.text-link {
    display: flex;
    align-items: center;
    min-height: 44px;
    font-size: 15px;
    font-weight: 500;
}

/* ---------- Page layout ---------- */

.home {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
        "band"
        "list"
        "side";
    max-width: var(--page);
    margin: 0 auto;
    padding: 0 var(--gutter);
}

.band-section { grid-area: band; }
.events-section { grid-area: list; min-width: 0; }
.sidebar { grid-area: side; min-width: 0; }

.section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s4);
    padding: var(--s4) 0 var(--s3);
}


.section-title {
    font-size: 16px;
    font-weight: 600;
}

.section-meta {
    font-size: var(--meta);
    color: var(--ink-2);
    font-variant-numeric: tabular-nums;
}

/* ---------- The date rail ---------- */

.rail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 var(--s3);
    padding: var(--s4) 0 var(--s2);
}

.rail-title { font-family: var(--font-display); font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.rail-range { font-size: var(--meta); color: var(--ink-2); font-variant-numeric: tabular-nums; }
.rail-head .view-switch { margin-left: auto; }
/* Under 360px the range drops below the title, so the switch keeps the title's line. */
@media (max-width: 359px) {
    .rail-head { align-items: center; }
    .rail-range { order: 3; flex-basis: 100%; }
}

/* Cards or rows: the kit's pill switch with two icon segments. */
.view-switch { display: flex; padding: 3px; border-radius: var(--radius-full); background: var(--stone); }
.view-btn {
    display: grid;
    place-items: center;
    width: 40px;
    height: 38px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: none;
    color: var(--ink-2);
    cursor: pointer;
    transition: background-color var(--duration-swap), color var(--duration-swap);
}
.view-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2px; }
.view-btn[aria-checked="true"] { background: var(--paper-raised); color: var(--ink); box-shadow: var(--shadow-raised); }
.view-btn:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: 2px; }

/* Rows view: the agenda under the rail replaces the cards. */
.home.is-rows .events-section { display: none; }

/* About six and a half days across a phone, the last cut off to show the row scrolls.
   It bleeds to the screen edge and snaps gently to a day. */
.rail {
    --gap: 4px;
    display: flex;
    gap: var(--gap);
    margin: 0 calc(-1 * var(--gutter));
    padding: var(--s1) var(--gutter) var(--s2);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }

.rail-day {
    flex: 1 0 max(48px, calc((100% - 6 * var(--gap)) / 6.6));
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-height: 74px;
    padding: var(--s2) 0 var(--s2);
    border: 0;
    border-radius: 14px;
    background: transparent;
    color: var(--ink);
    font: inherit;
    font-variant-numeric: tabular-nums;
    scroll-snap-align: start;
    cursor: pointer;
    transition: background-color var(--duration-swap), color var(--duration-swap);
}

@media (hover: hover) { .rail-day:not([aria-pressed="true"]):hover { background: var(--paper-raised); } }
.rail-day:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: 2px; }

.rail-dow { font-size: 12px; line-height: 16px; color: var(--ink-2); }
.rail-num { font-family: var(--font-display); font-size: 20px; line-height: 24px; font-weight: 600; }
.rail-day.is-today .rail-dow { color: var(--rail-accent); font-weight: 600; }

.rail-day[aria-pressed="true"] { background: var(--rail-sel); color: var(--on-rail-sel); }
.rail-day[aria-pressed="true"] .rail-dow { color: var(--on-rail-sel); }

/* One mark per event: its emoji, else its calendar's shape. An emoji glyph is wider than its
   font size (about 1.2em on iOS), so each box is sized to the glyph, never clipped. One or two
   marks read at 16px; three, or two and "+N", step down to 12px to sit abreast in a 48px day. */
.rail-marks { display: flex; align-items: center; justify-content: center; gap: 1px; height: 22px; margin-top: 2px; }
.rail-mark { display: grid; place-items: center; flex: none; width: 20px; height: 22px; }
.rail-mark .band-emoji { font-size: 16px; line-height: 1; }
.rail-mark .shape { width: 10px; height: 10px; }
.rail-marks:has(> :nth-child(3)) { gap: 0; }
.rail-marks:has(> :nth-child(3)) .rail-mark { width: 15px; }
.rail-marks:has(> :nth-child(3)) .band-emoji { font-size: 12px; }
.rail-marks:has(> :nth-child(3)) .shape { width: 8px; height: 8px; }
.rail-more { flex: none; font-size: 10px; line-height: 22px; font-weight: 700; letter-spacing: -0.02em; padding-left: 1px; }

/* At a month change, the new month's short name stands between the days. */
.rail-month {
    flex: none;
    align-self: center;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    padding: 0 2px;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--ink-2);
    border-right: 1px solid var(--hairline);
}

@media (min-width: 640px) {
    .rail-day { flex-basis: max(48px, calc((100% - 13 * var(--gap)) / 14)); }
}

/* ---------- The selected day's agenda ---------- */

.agenda {
    margin-top: var(--s1);
    padding-top: var(--s3);
    border-top: 1px solid var(--hairline);
}

.agenda-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); }
.agenda-title { font-family: var(--font-display); font-size: 16px; font-weight: 600; }
.agenda-count { font-size: var(--meta); color: var(--ink-2); font-variant-numeric: tabular-nums; }

.agenda-list { list-style: none; margin: var(--s2) 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

.agenda-row {
    display: grid;
    grid-template-columns: 44px 3px minmax(0, 1fr) auto;
    align-items: start;
    gap: 0 var(--s3);
    min-height: 48px;
    padding: var(--s2) 0;
    cursor: pointer;
}

.agenda-row .agenda-bar { align-self: stretch; }
.agenda-row.is-past .agenda-time,
.agenda-row.is-past .agenda-name { color: var(--ink-3); }

/* Quick sign-up: a small grey pill, the same Join as on a card. */
.agenda-join.btn { align-self: center; min-height: 36px; padding: 0 var(--s4); font-size: 14px; }
/* The rows sit on the page ground, which is the same grey as a line button; raise it instead. */
.agenda-join.btn.btn-line { background: var(--paper-raised); box-shadow: var(--shadow-raised); }
@media (hover: hover) { .agenda-join.btn.btn-line:hover:not(:disabled) { background: var(--stone); } }
.agenda-join.btn.btn-line:disabled { background: transparent; box-shadow: none; color: var(--ink-2); }

.agenda-time { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.agenda-bar { border-radius: 2px; background: var(--rail-accent); }
.agenda-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.agenda-main:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: 2px; border-radius: 4px; }
/* A tapped row opens under its title: the way to its card. */
.agenda-reveal { grid-column: 3 / -1; }
.agenda-reveal[hidden] { display: none; }
.agenda-to-card { min-height: 40px; }
.agenda-name { font-size: 15px; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.agenda-meta { font-size: 13px; color: var(--ink-2); overflow-wrap: anywhere; }
.agenda-empty { padding: var(--s2) 0; font-size: var(--meta); color: var(--ink-2); }

/* ---------- Back to top (Cards view) ---------- */

.to-top {
    position: fixed;
    right: max(var(--gutter), env(safe-area-inset-right));
    bottom: max(var(--s5), env(safe-area-inset-bottom));
    z-index: 40;
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--paper-raised);
    color: var(--ink);
    box-shadow: var(--shadow-raised);
    cursor: pointer;
}
.to-top svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2px; stroke-linecap: round; stroke-linejoin: round; }
@media (hover: hover) { .to-top:hover { background: var(--stone); } }
.to-top:focus-visible { outline: var(--stroke-2) solid var(--focus); outline-offset: 2px; }
.home.is-rows ~ .to-top { display: none; }

/* ---------- Pull to refresh ---------- */

/* Sits behind the page in the gap a pull opens; js/pull-to-refresh.js fills in the spokes. */
.ptr {
    position: fixed;
    inset: max(var(--s4), env(safe-area-inset-top)) 0 auto;
    z-index: 1;
    display: flex;
    justify-content: center;
    pointer-events: none;
    color: var(--ink-2);
}
.ptr line { stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; }
/* The iOS activity spinner: eight spokes that tick round rather than glide. */
.ptr-spinner.is-spinning svg { animation: ptr-spokes 800ms steps(8) infinite; }
@keyframes ptr-spokes { to { transform: rotate(360deg); } }

/* ---------- List controls ---------- */

.list-head {
    display: flex;
    align-items: center;
    gap: var(--s5);
    margin-top: var(--s6);
}

/* The kit's pill switch: a filled track, the active choice a raised pill. 3 + 38 + 3 = a 44px target. */
.range-switch {
    display: flex;
    padding: 3px;
    border-radius: var(--radius-full);
    background: var(--stone);
    margin-right: auto;
}

.range-btn {
    min-height: 38px;
    padding: 0 var(--s4);
    border: 0;
    border-radius: var(--radius-full);
    background: none;
    font-size: 15px;
    font-weight: 600;
    color: var(--ink-2);
    cursor: pointer;
    transition: background-color var(--duration-swap), color var(--duration-swap);
}

.range-btn:hover { color: var(--ink); }

.range-btn.active {
    background: var(--paper-raised);
    color: var(--ink);
    box-shadow: var(--shadow-raised);
}

.text-btn {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--meta);
    font-weight: 500;
    color: var(--ink);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    cursor: pointer;
}

.text-btn:hover { text-decoration-thickness: 2px; }
.text-btn:disabled { color: var(--ink-3); cursor: default; }

.legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--s5);
    margin: var(--s2) 0 var(--s3);
}

.legend-item {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: 44px;
    font-size: 15px;
    cursor: pointer;
    user-select: none;
}

.legend-item input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    margin: 0;
}

.legend-item .shape { font-size: 14px; }
.legend-item:has(input:focus-visible) { outline: var(--stroke-2) solid var(--focus); outline-offset: 2px; }
.legend-item.is-off { color: var(--ink-3); }
.legend-item.is-off .shape { fill: none; stroke: var(--ink-3); }

/* ---------- Events ---------- */

.event-list { min-height: 200px; }

.event {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr);
    gap: 0 var(--s4);
    margin-top: var(--s3);
    padding: var(--s5) var(--s4);
    border-radius: var(--radius-card);
    background: var(--paper-raised);
    box-shadow: var(--shadow-raised);
    scroll-margin-top: var(--s4);
}

.event-date {
    display: flex;
    flex-direction: column;
    font-variant-numeric: tabular-nums;
}

.event-day {
    font-size: 44px;
    font-weight: 500;
    line-height: 0.9;
    letter-spacing: -0.03em;
}

.event-daymeta {
    display: flex;
    flex-direction: column;
    margin-top: var(--s2);
    font-size: var(--meta);
    line-height: 1.3;
    color: var(--ink-2);
}

.event-mark {
    display: inline-block;
    margin-right: 8px;
    vertical-align: 0.02em;
}

.event-mark .shape { font-size: 0.62em; }

.event-time { color: var(--ink); font-weight: 500; }

.event-title {
    margin: 0 0 var(--s1);
    font-size: 20px;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    text-wrap: balance;
    overflow-wrap: anywhere;
}

.event-meta {
    font-size: var(--meta);
    color: var(--ink-2);
    overflow-wrap: anywhere;
}

/* An outbound link in the meta line: the one coloured, underlined text on Home, with an
   arrow, so it reads as a way out without becoming another button. */
.event-link {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    color: var(--link);
    font-weight: 500;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
}

.event-link svg {
    width: 12px;
    height: 12px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2px;
    stroke-linecap: square;
}

.event-link:hover { text-decoration-thickness: 2px; }

/* Inside an event the pill steps down a size, since every event carries one. */
.event-actions .btn {
    min-height: 40px;
    padding: 0 var(--s4);
}

.event-desc {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    max-width: 65ch;
    margin-top: var(--s3);
    font-size: 15px;
    color: var(--ink-2);
    overflow-wrap: anywhere;
}

.event.expanded .event-desc {
    display: block;
    -webkit-line-clamp: unset;
}

.event-desc-toggle { margin-top: -4px; }

/* Seats */

.seats {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s2) var(--s3);
    margin-top: var(--s4);
}

.slots {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
}

.slot { display: block; }
.slot .shape { font-size: 16px; fill: var(--paper); transform-origin: center; }
.slot.is-taken .shape { fill: var(--tone); }
.slot.is-new .shape { animation: shape-grow 480ms var(--ease) both; }
.seats.is-full .slot .shape { fill: var(--ink); }

.seats-label {
    font-size: var(--meta);
    color: var(--ink-2);
    font-variant-numeric: tabular-nums;
}

.seats.is-full .seats-label { color: var(--ink); font-weight: 600; }

/* Names */

.names {
    display: flex;
    flex-wrap: wrap;
    gap: 2px var(--s4);
    margin: var(--s3) 0 0;
    padding: 0;
    list-style: none;
    font-size: 15px;
}

.names li { overflow-wrap: anywhere; }
.names li.is-new { font-weight: 600; animation: name-print 700ms var(--ease) both; }

.names-empty {
    margin-top: var(--s3);
    font-size: var(--meta);
    color: var(--ink-3);
}

.event-actions {
    display: flex;
    align-items: center;
    gap: var(--s5);
    margin-top: var(--s5);
}

/* Past: every shape drains to a grey outline. */

.event.is-past .event-day,
.event.is-past .event-title { color: var(--ink-3); }
.event.is-past .shape { fill: none; stroke: var(--past); }

/* Pointed at from the band: its shapes step, nothing else moves. */
.event.is-pointed .slot .shape,
.event.is-pointed .event-mark .shape { animation: shape-step 520ms var(--ease); }

.today-rule {
    margin-top: var(--s5);
    padding: var(--s2) 0 var(--s3);
    border-top: 3px solid var(--ink);
    font-size: var(--meta);
    font-weight: 600;
    scroll-margin-top: var(--s4);
}

.today-rule + .event { margin-top: 0; }

.load-earlier-wrap { padding: var(--s2) 0 var(--s4); }

.state-line {
    padding: var(--s5) 0;
    border-top: var(--rule) solid var(--ink);
    font-size: 15px;
    color: var(--ink-2);
}

.state-line.is-error { color: var(--ink); font-weight: 500; }

/* ---------- Buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 0 var(--s5);
    border: 0;
    border-radius: var(--radius-full);
    text-decoration: none;
    cursor: pointer;
    transition: background-color 140ms var(--ease), color 140ms var(--ease);
}

/* Solid is the one main action in a form or sheet; line is everything else. Hover swaps
   fills, never fades: the kit's rule. Solid stays ink, because red belongs to a calendar. */
/* Filled, never outlined: solid is ink, line is a grey pill. Hover swaps to the next tone. */
.btn-solid { background: var(--ink); color: var(--paper); }
.btn-solid:hover { background: var(--ink-2); color: var(--paper); }

.btn-line { background: var(--fill); color: var(--ink); }
.btn-line:hover { background: var(--stone); color: var(--ink); }

.btn:disabled,
.btn[disabled] {
    background: var(--fill);
    color: var(--ink-3);
    cursor: not-allowed;
}

/* ---------- Sidebar: calendar links, support ---------- */

.sidebar { margin-top: var(--s7); }

.side-block + .side-block {
    margin-top: var(--s3);
}

/* A raised card, like an event. */
.side-block {
    padding: var(--s4);
    border-radius: var(--radius-card);
    background: var(--paper-raised);
    box-shadow: var(--shadow-raised);
}

.side-title {
    font-size: 16px;
    font-weight: 600;
    margin-bottom: var(--s3);
}

.side-note {
    margin-top: var(--s3);
    font-size: var(--meta);
    color: var(--ink-2);
}

.side-block .btn { width: 100%; }

.subscribe-list {
    display: flex;
    flex-direction: column;
    margin-top: var(--s1);
}

.subscribe-link {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    min-height: 44px;
    font-size: 15px;
}

.subscribe-link .shape { font-size: 13px; }

/* ---------- Sheets (RSVP) ---------- */

.modal {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    background: var(--scrim);
}

.modal.hidden { display: none; }

.sheet {
    position: relative;
    width: 100%;
    max-width: 480px;
    max-height: 92vh;
    overflow-y: auto;
    padding: 28px var(--gutter) calc(var(--s5) + env(safe-area-inset-bottom));
    background: var(--paper-raised);
    border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
    box-shadow: var(--shadow-float);
    animation: sheet-in var(--duration-sheet) var(--ease-sheet);
}

/* Phones: the sheet slides up from the bottom edge, with a grabber on top.
   Wider screens slide it in from the right as a full-height panel. */
.sheet::before {
    content: "";
    position: absolute;
    top: var(--s2);
    left: 50%;
    width: 36px;
    height: 4px;
    margin-left: -18px;
    border-radius: var(--radius-full);
    background: var(--hairline);
}

@keyframes sheet-in {
    from { transform: translateY(100%); }
}
@keyframes drawer-in {
    from { transform: translateX(100%); }
}
@keyframes pop-in {
    from { opacity: 0; transform: scale(0.96); }
}

.sheet-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--s3);
    margin-right: -10px;
}

.sheet-head .icon-btn { flex: none; width: 32px; height: 32px; margin: 0 10px 0 0; background: var(--fill); }
.sheet-head .icon-btn:hover { background: var(--stone); }
.sheet-head .icon-btn svg { width: 16px; height: 16px; stroke-width: 2px; }

.sheet-title {
    padding-top: var(--s2);
    font-size: 22px;
    font-weight: 600;
    line-height: 1.25;
    text-wrap: balance;
}

.sheet-when {
    margin-top: var(--s1);
    font-size: var(--meta);
    color: var(--ink-2);
}

.sheet-desc {
    max-height: 7.5em;
    overflow-y: auto;
    margin-top: var(--s3);
    font-size: var(--meta);
    color: var(--ink-2);
    overflow-wrap: anywhere;
}

.sheet-desc[hidden] { display: none; }

.field { margin-top: var(--s5); }

/* 12px clears the focus ring (2px outline, 2px offset) with room to spare. */
.field label {
    display: block;
    margin-bottom: var(--s3);
}

.field-label-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--s3);
}

.field-label-row label { margin-bottom: 0; }
.field-label-row .text-btn { min-height: 36px; }

.input {
    display: block;
    width: 100%;
    min-height: 50px;
    padding: 0 var(--s3);
    border: var(--stroke-2) solid transparent;
    border-radius: var(--radius-control);
    background-color: var(--fill);
    color: var(--ink);
    font: inherit;
    font-size: 17px;
    -webkit-appearance: none;
    appearance: none;
}

.input::placeholder { color: var(--ink-3); }
.input:focus { outline: var(--stroke-2) solid var(--focus); outline-offset: 2px; }

.select {
    padding-right: 44px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23161616' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 20px;
}

.field-error {
    display: flex;
    align-items: center;
    gap: var(--s2);
    margin-top: var(--s2);
    font-size: var(--meta);
    font-weight: 500;
}

.field-error::before {
    content: "";
    flex: none;
    width: 8px;
    height: 8px;
    background: var(--ink);
}

.field-error[hidden] { display: none; }

.sheet-actions {
    display: flex;
    align-items: center;
    gap: var(--s5);
    margin-top: var(--s5);
}

.sheet-actions .btn { flex: 1 1 auto; }

/* ---------- Colophon ---------- */

/* The rule sits on the footer itself, so the footer is sized to the content column
   (the page width less both gutters) rather than padded out to the page width. */
.colophon {
    width: calc(100% - 2 * var(--gutter));
    max-width: calc(var(--page) - 2 * var(--gutter));
    margin: var(--s8) auto 0;
    padding-bottom: var(--s6);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0 var(--s5);
    border-top: var(--rule) solid var(--ink);
    padding-top: var(--s2);
}

.colophon p {
    font-size: 13px;
    color: var(--ink-3);
}

/* Theme: Auto · Light · Dark. Footer-sized, but each choice is a 44px touch target. */
.theme-switch {
    display: flex;
    align-items: center;
    gap: var(--s3);
    font-size: 13px;
    color: var(--ink-3);
}

.theme-btn {
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: var(--ink-3);
    cursor: pointer;
}

.theme-btn:hover { color: var(--ink); }

.theme-btn[aria-pressed="true"] {
    color: var(--ink);
    font-weight: 500;
    text-decoration: underline;
    text-decoration-thickness: var(--rule);
    text-underline-offset: 4px;
}

/* Feedback: a footer-sized link that opens its sheet (js/feedback.js). */
.feedback-btn {
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 13px;
    color: var(--ink-3);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    cursor: pointer;
}

.feedback-btn:hover { color: var(--ink); }

.textarea {
    min-height: 140px;
    padding: var(--s3);
    line-height: 1.45;
    resize: vertical;
}

.feedback-files {
    display: flex;
    flex-direction: column;
    gap: var(--s2);
    margin: var(--s5) 0 0;
    padding: 0;
    list-style: none;
}

.feedback-files[hidden] { display: none; }

.feedback-files li {
    display: flex;
    align-items: center;
    gap: var(--s2);
    min-height: 44px;
    padding-left: var(--s3);
    border-radius: var(--radius-control);
    background: var(--fill);
}

.feedback-file-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--meta);
}

.feedback-files .icon-btn { flex: none; width: 44px; height: 44px; background: none; }
.feedback-files .icon-btn svg { width: 16px; height: 16px; stroke-width: 2px; }
.feedback-attach { margin-top: var(--s3); }
.feedback-attach[hidden] { display: none; }

/* ---------- Breakpoints ---------- */

/* Phones: a tighter header, so the first event lands in the first screen. */
@media (max-width: 639px) {
    .masthead { gap: var(--s3); }
    .wordmark { gap: var(--s2); }
    .list-head { margin-top: var(--s4); }
    .legend { margin-bottom: var(--s1); }
}

@media (min-width: 640px) {
    :root { --gutter: 32px; }


    .event { grid-template-columns: 72px minmax(0, 1fr); gap: 0 var(--s5); padding: var(--s5); }
    .event-day { font-size: 52px; }

    .modal { align-items: stretch; justify-content: flex-end; }
    .sheet {
        max-width: 420px;
        max-height: none;
        border-radius: var(--radius-sheet) 0 0 var(--radius-sheet);
        padding: var(--s5);
        animation-name: drawer-in;
    }
    .sheet::before { display: none; }
}

@media (min-width: 1000px) {
    .masthead { padding-top: var(--s4); padding-bottom: var(--s4); }

    .home {
        grid-template-columns: minmax(0, 1fr) 320px;
        grid-template-areas:
            "band band"
            "list side";
        column-gap: var(--s8);
    }
    /* Rows view has no card list, so the rail and its rows take the left column. */
    .home.is-rows { grid-template-areas: "band side"; }
    .home.is-rows .sidebar { margin-top: var(--s4); }


    .sidebar {
        align-self: start;
        position: sticky;
        top: var(--s4);
        margin-top: var(--s6);
    }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
    }
}
