/* ===========================================================================
   AIS Vienna, Class of 2007 — reunion signup
   A form-driven utility. Calm, institutional, legible on a phone at night.
   Palette from the school badge: deep green #154734, bright green #00aa66.

   1 tokens · 2 reset · 3 layout · 4 type · 5 forms · 6 buttons · 7 weekends
   8 pick list · 9 roster · 10 admin · 11 notices & panels · 12 print
   ======================================================================== */

/* --- 1. Tokens ---------------------------------------------------------- */

:root {
  color-scheme: light dark;

  --green: #154734;        /* deep badge green; white on it = 10.7:1 */
  --green-deep: #0e3325;   /* hover / pressed */
  --accent: #00aa66;       /* 3.0:1 on white — borders and fills only */
  --accent-ink: #007a48;   /* the accent when it must carry text, 5.0:1 */
  --accent-soft: #e7f6ee;
  --accent-line: #a9dfc4;

  --paper: #f6f7f4;        /* warmed a shade toward the green */
  --surface: #ffffff;
  --ink: #1b2420;          /* 14.6:1 on paper */
  --muted: #56635c;        /* 5.8:1 on paper */
  --line: #dfe3dd;
  --line-strong: #bec7bf;

  --danger: #a1291f;       /* 7.4:1 on white, 6.4:1 on its own tint */
  --danger-soft: #fbecea;
  --danger-line: #edbdb7;

  --w: 34rem;              /* page column */
  --text-w: 46rem;         /* measure for prose and lists on wide pages */
  --pad: 1.25rem;
  --radius: 8px;
  --radius-lg: 12px;
  --tap: 2.75rem;          /* 44px */

  --shadow: 0 1px 2px rgba(21, 71, 52, .06), 0 2px 10px rgba(21, 71, 52, .05);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

body.wide { --w: 76rem; }

@media (prefers-color-scheme: dark) {
  :root {
    --green: #1f7a55;      /* white on it = 5.3:1 */
    --green-deep: #196345;
    --accent: #2ec98a;
    --accent-ink: #5fe0a8; /* 11:1 on the dark paper */
    --accent-soft: #14291f;
    --accent-line: #2c5a45;

    --paper: #0f1512;
    --surface: #17201b;
    --ink: #e6ece7;        /* 15.4:1 */
    --muted: #9fb0a6;      /* 8.2:1 */
    --line: #29332d;
    --line-strong: #3d4a43;

    --danger: #f0a49a;
    --danger-soft: #2a1a17;
    --danger-line: #5a342e;
    --shadow: 0 1px 2px rgba(0, 0, 0, .45);
  }
}

/* --- 2. Reset ----------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 1rem/1.55 var(--font);
  overflow-x: clip;        /* never sideways; clip, not hidden, keeps sticky */
}

[hidden] { display: none !important; }   /* app.js toggles this attribute */

:focus-visible { outline: 3px solid var(--accent-ink); outline-offset: 2px; }
::selection { background: var(--accent-line); color: var(--green-deep); }

/* --- 3. Layout ---------------------------------------------------------- */
/* Full-bleed bands with a centred content column; no wrapper divs exist,
   so the column is made with padding rather than an inner element. */

header.site, main, footer.site {
  --gutter: max(var(--pad), calc((100% - var(--w)) / 2));
  padding-left: var(--gutter); padding-right: var(--gutter);
}

header.site {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: .4rem 1.25rem; padding-top: .75rem;
  padding-bottom: .75rem; background: var(--surface);
  border-bottom: 1px solid var(--line);
}

main { padding-top: 1.75rem; padding-bottom: 3.5rem; }
main > * { max-width: var(--text-w); }   /* keeps prose readable when wide */

footer.site {
  padding-top: 1.5rem; padding-bottom: 2.5rem; border-top: 1px solid var(--line);
  color: var(--muted); font-size: .875rem;
}

.brand {
  display: flex; align-items: center; gap: .7rem; min-height: var(--tap);
  color: inherit; text-decoration: none;
}
.brand-mark {
  flex: none; display: grid; place-items: center; width: 2.25rem; height: 2.25rem;
  border-radius: 6px; background: var(--green); color: #fff; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.brand-text { display: flex; flex-direction: column; line-height: 1.25; }
.brand-text strong { font-size: .95rem; }
.brand-text small { color: var(--muted); font-size: .78rem; }

/* Header and filter navs */
.site-nav, .admin-nav, .filters {
  display: flex; flex-wrap: wrap; gap: .25rem 1rem; align-items: center;
}
.site-nav a, .admin-nav a, .filters a {
  display: inline-flex; align-items: center; min-height: var(--tap);
  color: var(--accent-ink); font-size: .9rem; font-weight: 600;
  text-decoration: none; border-bottom: 2px solid transparent;
}
.site-nav a:hover, .admin-nav a:hover, .filters a:hover {
  color: var(--accent-ink); border-bottom-color: var(--accent);
}
.filters { margin-bottom: 1rem; }
.filters a.current { color: var(--ink); border-bottom-color: var(--green); font-weight: 700; }

/* Six admin links used to wrap 5 + 1, stranding "Admins" alone on a second
   line under a band of white. Three columns is deterministic: two balanced
   rows whatever the labels or the font metrics do. */
@media (max-width: 46rem) {
  .admin-nav {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 .6rem;
    width: 100%;
  }
  .admin-nav a { min-height: 2.25rem; }
}

/* --- 4. Type ------------------------------------------------------------ */

h1, h2, h3 { line-height: 1.2; margin: 0 0 .5rem; font-weight: 650; }
h1 { font-size: 1.6rem; letter-spacing: -.015em; }
h2 { font-size: 1.2rem; margin-top: 2rem; }
h3 { font-size: 1rem; }
main > h1:first-child, .gate h1, .card h2:first-child { margin-top: 0; }

p { margin: 0 0 .9rem; }
a { color: var(--accent-ink); text-underline-offset: 2px; }
a:hover { color: var(--green); }

.lede { font-size: 1.05rem; color: var(--muted); }
.hint, .maiden, .private, .gap, small {
  font-size: .875rem; font-weight: 400; color: var(--muted);
}
/* "at school: Filipp" is one phrase; it may wrap before it, never inside it. */
.maiden { font-size: .8rem; white-space: nowrap; }
.hint { display: block; margin: -.15rem 0 .5rem; }
code { font-family: var(--mono); font-size: .9em; }

/* --- 5. Forms ----------------------------------------------------------- */

form { margin: 0; }
fieldset { border: 0; margin: 0 0 1rem; padding: 0; min-width: 0; }
legend { padding: 0; }

label { display: block; margin-bottom: .3rem; font-size: .95rem; font-weight: 600; }

input[type="text"], input[type="email"], input[type="tel"], input[type="number"],
input[type="password"], input[type="search"], input[type="url"],
input:not([type]), textarea, select {
  display: block;
  width: 100%;
  min-height: var(--tap);
  margin-bottom: 1.1rem;
  padding: .6rem .7rem;
  font: inherit;
  font-size: 1rem;         /* 16px — stops iOS zooming on focus */
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  appearance: none;
}
textarea { min-height: 6rem; line-height: 1.5; resize: vertical; }
::placeholder { color: var(--muted); opacity: 1; }
input:focus, textarea:focus, select:focus { border-color: var(--accent-ink); }

input:disabled, textarea:disabled, select:disabled {
  background: var(--paper); color: var(--muted); border-style: dashed;
  cursor: not-allowed;
}
/* Error: tint plus a heavy left rule, so it is never colour alone.
   The element name is on every selector here on purpose: a bare
   `[aria-invalid="true"]` scores 0-1-0 and loses to the `input[type="tel"]`
   base rule above, which is why this block used to do nothing when the
   attribute was finally emitted. */
input:user-invalid, textarea:user-invalid,
input[aria-invalid="true"], textarea[aria-invalid="true"],
select[aria-invalid="true"], input.error {
  border-color: var(--danger); border-left-width: 4px;
  background: var(--danger-soft);
}

input[type="checkbox"], input[type="radio"] {
  flex: none; width: 1.3rem; height: 1.3rem; margin: .15rem 0 0;
  accent-color: var(--green);
}

/* A checkbox and its label are one large target. */
label.check {
  display: flex; align-items: flex-start; gap: .7rem; min-height: var(--tap);
  margin: 0 0 .5rem; padding: .6rem .8rem; font-weight: 400;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer;
}
label.check strong { font-weight: 650; }
label.check small { display: block; }
label.check:hover { border-color: var(--line-strong); }
label.check:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
label.check:has(input:focus-visible) { outline: 3px solid var(--accent-ink); outline-offset: 2px; }

/* --- 6. Buttons --------------------------------------------------------- */

button, .button {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  width: 100%; min-height: var(--tap); margin-bottom: .5rem;
  padding: .65rem 1.25rem; font: inherit; font-weight: 650; color: #fff;
  text-align: center; text-decoration: none; background: var(--green);
  border: 1px solid var(--green); border-radius: var(--radius); cursor: pointer;
}
@media (min-width: 30rem) { button, .button { width: auto; } }

button:hover, .button:hover {
  color: #fff; background: var(--green-deep); border-color: var(--green-deep);
}
button:active { transform: translateY(1px); }
button:disabled {
  background: var(--line); border-color: var(--line); color: var(--muted);
  cursor: not-allowed; transform: none;
}

/* Secondary, outlined */
button.secondary, .button.secondary {
  color: var(--green); background: var(--surface); border-color: var(--line-strong);
}
button.secondary:hover, .button.secondary:hover {
  color: var(--green); background: var(--paper); border-color: var(--green);
}
@media (prefers-color-scheme: dark) {
  button.secondary, .button.secondary { color: var(--accent-ink); }
  button.secondary:hover { color: var(--accent-ink); }
}

/* Quiet: reads as a link, still a 44px target */
button.link, button.linky {
  width: auto; padding: .3rem .4rem; color: var(--accent-ink); background: none;
  border-color: transparent; font-weight: 600; text-decoration: underline;
  text-underline-offset: 3px;
}
button.link:hover, button.linky:hover {
  color: var(--green); background: var(--accent-soft); border-color: transparent;
}

/* Small */
button.small, .actions button {
  width: auto; min-height: 2.25rem; padding: .3rem .7rem; font-size: .875rem;
}

.inline-form { margin: -.25rem 0 1.25rem; }
.logout { margin-top: 2.5rem; }

/* --- 7. Weekend picker -------------------------------------------------- */

.attendee-list { columns: 2 14rem; padding-left: 1.25rem; }
.attendee-list li { break-inside: avoid; padding: .3rem 0; }

.weekend {
  margin: 0 0 .75rem; padding: .9rem 1rem; background: var(--surface);
  border: 1px solid var(--line-strong); border-left: 4px solid var(--line-strong);
  border-radius: var(--radius-lg);
}
.weekend > label.check {
  margin: 0; padding: 0; min-height: var(--tap); background: none; border: 0;
}
.weekend > label.check strong { font-size: 1.05rem; letter-spacing: -.01em; }
.weekend > label.check small { color: var(--muted); margin-top: .1rem; }

/* Selected: tint, accent rules and a shadow — but the checked box itself is
   the primary, non-colour signal. */
.weekend:has(> label.check:not(.nested) input:checked) {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: var(--shadow);
}
.weekend:has(> label.check:not(.nested) input:checked) > label.check:not(.nested) {
  background: none;
}
.weekend:has(input:focus-visible) { outline: 3px solid var(--accent-ink); outline-offset: 2px; }

/* The nested brunch option, indented under its weekend */
label.check.nested {
  margin: .7rem 0 0 1.9rem; padding: .35rem .6rem .35rem .7rem; background: none;
  border: 0; border-left: 2px solid var(--line-strong); border-radius: 0;
  font-size: .92rem; color: var(--muted);
}
.weekend:has(> label.check:not(.nested) input:checked) label.check.nested {
  border-left-color: var(--accent); color: var(--ink);
}

/* --- 8. Identify pick list ---------------------------------------------- */

/* Sticky search: stays reachable while thumbing through 188 names. */
.filter {
  position: sticky; top: 0; z-index: 5; margin: 1.25rem 0 .75rem;
  padding: .75rem 0 .1rem; background: var(--paper);
  border-bottom: 1px solid var(--line);
}
.filter input { margin-bottom: .5rem; }
.filter .hint { margin: 0 0 .5rem; }

.picklist { list-style: none; margin: 0 0 1.5rem; padding: 0; }
.pick { border-bottom: 1px solid var(--line); }
.pick:first-child { border-top: 1px solid var(--line); }
.pick button {
  width: 100%; margin: 0; padding: .6rem .5rem; color: var(--ink); font-weight: 500;
  text-align: left; justify-content: flex-start; background: none; border: 0;
  border-radius: 0;
}
.pick button:hover { color: var(--green); background: var(--accent-soft); border: 0; }

/* --- 9. Roster ---------------------------------------------------------- */
/* One row per person, 188 of them. The rows we can't reach are the point of
   the page, so they carry a heavy accent rule, a tint and the words "needs
   details" — three cues, only one of them colour. Each row is a <details>
   that ships open; app.js folds it shut. */

.roster-controls, .roster, .roster-empty, .roster-hint { max-width: 62rem; }

/* Only the tabs and the search box stick. The count line used to live in here
   too, and between it, two wrapped lines of filter tabs and the field, the bar
   stood 210px tall — 31% of an iPhone SE, leaving 5 of 192 rows visible. The
   hint is now an ordinary paragraph outside the sticky region. */
.roster-controls {
  position: sticky; top: 0; z-index: 5; margin: 1.25rem 0 0;
  padding: .5rem 0 .35rem; background: var(--paper);
  border-bottom: 1px solid var(--line);
}
.roster-hint { margin: .55rem 0 .5rem; }
.roster-search label {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.roster-search input { margin-bottom: 0; }

/* Filter links, with the size of each set spelled out */
.roster-filters { gap: .1rem .9rem; margin-bottom: .4rem; }
.roster-filters a { gap: .35rem; }
.roster-filters .n {
  padding: .05rem .4rem; border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--surface); color: var(--muted); font-size: .75rem;
  font-variant-numeric: tabular-nums;
}
.roster-filters a.current .n { border-color: var(--green); color: var(--ink); }

/* Two labels per tab, one shown at a time — so only one is ever in the
   accessibility tree, and the narrow screen gets three tabs on one line
   instead of the third orphaned under the first. */
.lab-short { display: none; }

/* On a phone the three tabs become one compact segmented control that scrolls
   sideways if it has to, rather than wrapping onto a second 44px line. */
@media (max-width: 46rem) {
  .lab-long { display: none; }
  .lab-short { display: inline; }

  .roster-controls { padding: .35rem 0 .3rem; }
  .roster-filters {
    flex-wrap: nowrap; gap: 0; margin-bottom: .35rem;
    overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
    background: var(--surface); border: 1px solid var(--line-strong);
    border-radius: var(--radius);
  }
  .roster-filters::-webkit-scrollbar { display: none; }
  .roster-filters a {
    flex: 1 0 auto; justify-content: center; min-height: 2.5rem;
    padding: 0 .55rem; border-bottom: 0; white-space: nowrap;
  }
  .roster-filters a + a { border-left: 1px solid var(--line); }
  /* Weight and the count pill's rule carry the current state, not colour alone. */
  .roster-filters a.current {
    background: var(--accent-soft); color: var(--ink);
    box-shadow: inset 0 -3px 0 var(--green);
  }
  .roster-filters a:hover { border-bottom-color: transparent; }
  .roster-hint { margin: .45rem 0 .4rem; }
}

/* Landing on a row from `#person-N` must not put it under the sticky bar. */
.person, .add-person { scroll-margin-top: 8rem; }
.add-person:focus { outline: none; }
.add-person:focus-visible { outline: 3px solid var(--accent-ink); outline-offset: 2px; }

/* Skip link: invisible until it is focused, so it costs nothing visually and
   saves a keyboard user 274 tab presses to reach "add someone we've missed". */
.skip {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.skip:focus {
  position: static; width: auto; height: auto; overflow: visible;
  clip-path: none; display: inline-block; margin: 0 0 .9rem;
  padding: .5rem .8rem; background: var(--surface);
  border: 1px solid var(--green); border-radius: var(--radius);
  font-weight: 600;
}

.roster { list-style: none; margin: 0 0 1.5rem; padding: 0; }
.person {
  border-bottom: 1px solid var(--line); border-left: 4px solid transparent;
}
.person:first-child { border-top: 1px solid var(--line); }

/* The actionable state. */
.person[data-state="missing"] {
  border-left-color: var(--accent); background: var(--accent-soft);
}
/* Details on file, deliberately not shown: dotted rule, hatched ground. */
.person[data-state="private"] {
  border-left: 4px dotted var(--line-strong);
  background: repeating-linear-gradient(-45deg,
    transparent 0 6px, rgba(128, 140, 132, .07) 6px 12px);
}

/* Under the "Missing" filter every row is a missing row, so the tint, the
   accent rule and the chip all say the same thing 113 times and none of them
   distinguishes anything. Keep them on "Everyone", where they do real work,
   and give the view where you scroll most its line of height back. The filter
   nav's data-show is kept current by app.js as well as by the server, so this
   holds whether the switch was a page load or a click. */
.roster-controls:has(.roster-filters[data-show="missing"]) ~ .roster
  .person[data-state="missing"] {
  background: none; border-left-color: transparent;
}
.roster-controls:has(.roster-filters[data-show="missing"]) ~ .roster .chip.need {
  display: none;
}

.person > details > summary { list-style: none; }
.person > details > summary::-webkit-details-marker { display: none; }

.row-summary {
  display: grid; align-items: center; gap: .1rem .8rem;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "name action" "status action" "city action";
  min-height: var(--tap); padding: .45rem .7rem; cursor: pointer;
}
.row-summary:hover { background: rgba(0, 170, 102, .06); }
.row-name { grid-area: name; font-weight: 600; }
.row-status { grid-area: status; display: flex; align-items: center; gap: .4rem; min-width: 0; }
.row-city { grid-area: city; color: var(--muted); font-size: .875rem; }
.row-city:empty { display: none; }
.row-action {
  grid-area: action; justify-self: end; color: var(--accent-ink);
  font-size: .8rem; font-weight: 600; white-space: nowrap;
}
.row-action::after { content: " \25B8"; }
details[open] .row-action::after { content: " \25BE"; }
.row-summary:hover .row-action { color: var(--green); text-decoration: underline; }

.row-email {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: .875rem;
}

@media (min-width: 46rem) {
  .row-summary {
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1.6fr) minmax(0, .9fr) auto;
    grid-template-areas: "name status city action";
  }
  .row-city:empty { display: block; }
}

/* Status chips: the word carries the meaning, the colour only reinforces it. */
.chip {
  display: inline-flex; align-items: center; padding: .05rem .45rem;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--surface); color: var(--muted); font-size: .7rem;
  font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  white-space: nowrap;
}
.chip.need { border-color: var(--accent); color: var(--accent-ink); }
.chip.priv { border-style: dotted; }

/* Contact on file: a filled disc holding the ✓ the roster emits. */
.tick {
  flex: none; display: inline-grid; place-items: center; width: 1.35rem;
  height: 1.35rem; border-radius: 50%; background: var(--accent-ink); color: #fff;
  font-size: .8rem; line-height: 1;
}
@media (prefers-color-scheme: dark) { .tick { color: var(--paper); } }

/* The panel under a row */
.row-panel {
  padding: .2rem .9rem .8rem 1rem; border-top: 1px dashed var(--line);
}
.row-panel .notice { margin-top: .6rem; }
.details { margin: .5rem 0 .2rem; font-size: .95rem; }
.gap { margin: .5rem 0 .4rem; }
.row-panel .hint { margin: 0 0 .35rem; }

/* The explanation on a private row. The hatched ground is on the row itself. */
.private {
  margin: .5rem 0 .3rem;
  padding: .5rem .7rem;
  border-left: 3px dotted var(--line-strong);
  font-style: italic;
}
.private a { font-style: normal; }

/* Inline correction form, indented under the row it belongs to */
.correction {
  margin: .5rem 0 .25rem; padding: .8rem .9rem .2rem; background: var(--surface);
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}
.correction input { margin-bottom: .8rem; }
.correction label { font-size: .85rem; }

/* --- 10. Admin ---------------------------------------------------------- */

.counts { margin: 0 0 1rem; padding-left: 1.1rem; }
.counts li { margin-bottom: .2rem; }

/* Weekend tally */
.tally {
  display: grid; gap: .75rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); max-width: 100%;
  margin-bottom: 1.5rem;
}
.tally-card {
  padding: .9rem 1rem; background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--line-strong); border-radius: var(--radius);
  font-size: .875rem; color: var(--muted);
}
.tally-card h3 { margin-bottom: .1rem; color: var(--ink); }
.tally-card p { margin: 0 0 .15rem; }
.tally-card .dates { color: var(--ink); font-weight: 600; }
.tally-card .big {
  margin: .3rem 0 .2rem; font-size: 1.7rem; font-weight: 700; line-height: 1.1;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.tally-card.leading { border-top-color: var(--accent); background: var(--accent-soft); }
.leading-flag {
  display: inline-block; margin-top: .4rem !important; padding: .1rem .5rem;
  border: 1px solid var(--accent); border-radius: 999px; color: var(--accent-ink);
  font-size: .72rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase;
}

/* Dense tables. admin.js emits no wrapper, so the table is its own scroll
   pane: it scrolls in both axes and the page body never moves sideways. */
table.grid {
  display: block; max-width: 100%; max-height: min(78vh, 46rem); margin: 0 0 1.5rem;
  overflow: auto; overscroll-behavior: contain; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--surface);
  border-collapse: collapse; font-size: .85rem; font-variant-numeric: tabular-nums;
}
table.grid th, table.grid td {
  padding: .45rem .65rem; text-align: left; vertical-align: top;
  white-space: nowrap; border-bottom: 1px solid var(--line);
}
table.grid thead th {
  position: sticky; top: 0; z-index: 2; background: var(--paper);
  border-bottom: 2px solid var(--line-strong); color: var(--muted);
  font-size: .72rem; letter-spacing: .06em; text-transform: uppercase;
}
table.grid tbody tr:nth-child(even) { background: var(--paper); }
table.grid tbody tr:hover { background: var(--accent-soft); }
table.grid td.notes { white-space: normal; min-width: 18rem; }
tr.reverted td { color: var(--muted); text-decoration: line-through; }
tr.reverted td:first-child { box-shadow: inset 3px 0 0 var(--line-strong); }

/* Buttons living inside a table cell */
td.actions { display: table-cell; white-space: nowrap; }
td.actions form { display: inline-block; margin-right: .3rem; }
td.actions button { margin-bottom: 0; }

/* Key/value detail tables are not scroll panes.
   The label column used to be `width: 11rem`, a preferred width auto table
   layout will not shrink below: on a 375px phone that pushed the value column
   past the right edge, and because `body { overflow-x: clip }` the page could
   not be panned to reach it — content silently cut off, not merely awkward.
   A percentage shrinks with the table, and long unbroken values (an email, a
   URL in a note) now break rather than force the table wide. */
table.grid.detail { display: table; width: 100%; max-height: none; overflow: visible; }
table.grid.detail th {
  width: 40%; max-width: 11rem; color: var(--muted); font-weight: 600;
  white-space: normal; overflow-wrap: anywhere;
}
table.grid.detail td { white-space: normal; overflow-wrap: anywhere; }

/* Only a wide scroll pane needs the "there is more sideways" nudge. */
.scroll-hint { display: none; }
@media (max-width: 46rem) { .scroll-hint { display: block; } }

.flag {
  display: inline-block; margin-left: .3rem; padding: .05rem .4rem;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--paper); color: var(--muted); font-size: .7rem; font-weight: 700;
  letter-spacing: .03em; white-space: nowrap;
}

/* Copy-ready recipient string */
/* 1rem, not .85rem: below 16px iOS zooms the page the moment it is focused,
   and this was the only field on the site under that threshold. */
#email-list {
  min-height: 9rem; font-family: var(--mono); font-size: 1rem; line-height: 1.6;
  word-break: break-all; background: var(--surface);
}
#email-count { font-weight: 600; }

/* --- 11. Notices, panels, gate ------------------------------------------ */

.notice {
  margin: 0 0 1.25rem; padding: .7rem .9rem; background: var(--surface);
  border: 1px solid var(--line-strong); border-left: 4px solid var(--muted);
  border-radius: var(--radius); font-size: .95rem;
}
.notice ul { margin: 0; padding-left: 1.1rem; }
.notice li + li { margin-top: .25rem; }
/* A word prefixes each variant, so colour is never the only cue. */
.notice::before {
  display: block; margin-bottom: .1rem; font-size: .72rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
}
.notice.info { border-left-color: var(--green); }
.notice.info::before { content: "Note"; color: var(--muted); }
.notice.error {
  border-color: var(--danger-line); border-left-color: var(--danger);
  background: var(--danger-soft);
}
.notice.error::before { content: "Problem"; color: var(--danger); }
.notice.ok, .notice.success {
  border-color: var(--accent-line); border-left-color: var(--accent);
  background: var(--accent-soft);
}
.notice.ok::before, .notice.success::before { content: "Done"; color: var(--accent-ink); }

/* Secondary sections: add yourself, add someone missing, next step */
.add-self, .add-person, .cta, .card {
  margin: 2.5rem 0 0; padding: 1.1rem 1.1rem .2rem; background: var(--surface);
  border: 1px solid var(--line); border-top: 3px solid var(--green);
  border-radius: var(--radius-lg);
}
.add-self h2, .add-person h2, .cta h2 { margin-top: 0; }
.cta { border-top-color: var(--accent); padding-bottom: .8rem; }
.response-summary dt { font-weight: 600; margin-top: 1rem; }
.response-summary dd { margin: .25rem 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.summary { margin: 0 0 1rem; padding-left: 1.1rem; }

.gate {
  max-width: 26rem; margin: 1.5rem auto; padding: 1.5rem 1.25rem .5rem;
  background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--green); border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.gate h1 { font-size: 1.35rem; }
.gate .lede { font-size: 1rem; margin-bottom: 1.25rem; }
.gate button { width: 100%; }

/* --- 12. Motion and print ----------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  button:active { transform: none; }
}

@media print {
  :root {
    --paper: #fff; --surface: #fff; --ink: #000; --muted: #333;
    --line: #bbb; --line-strong: #888; --accent-soft: #fff; --shadow: none;
  }
  body, body.wide { --w: 100%; --text-w: 100%; background: #fff; font-size: 10pt; }
  header.site nav, footer.site, .filter, .roster-controls, .row-action,
  .logout, .correction,
  .add-self, .add-person, .cta, button, .button { display: none !important; }
  header.site { border-bottom: 1pt solid #000; padding: 0 0 .5rem; }
  main { padding-top: 1rem; }
  .gate, .card, .tally-card { border: 1px solid #bbb; }
  table.grid { display: table; max-height: none; overflow: visible; }
  table.grid thead th { position: static; }
  .person, tr, .weekend, .tally-card { break-inside: avoid; }
  a { color: #000; text-decoration: underline; }
}

/*
 * /coming — the weekend grid
 *
 * Every colour here is a token, never a literal. The first cut hardcoded
 * light-mode hex and the whole block inverted badly in dark mode. The tokens
 * above already carry both schemes with their contrast ratios worked out.
 */
.coming { width: 100%; border-collapse: collapse; margin: 1.5rem 0; }
.coming th, .coming td { padding: 0.5rem 0.4rem; text-align: left; border-bottom: 1px solid var(--line); }
.coming thead th { font-size: 0.85rem; font-weight: 600; vertical-align: bottom; color: var(--muted); }
.coming td.w { text-align: center; width: 6.5rem; }
.coming td.w.yes { color: var(--accent-ink); font-weight: 700; }
.coming tfoot .totals th, .coming tfoot .totals td { border-top: 2px solid var(--accent-ink); border-bottom: none; font-weight: 700; }
.coming tfoot .totals td { text-align: center; }
.coming-none ul.plain { list-style: none; padding: 0; }
.coming-none ul.plain li { padding: 0.15rem 0; }
/* Visible to a screen reader, not on screen. The tick is decorative. */
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* The landing hub */
.tiles { display: grid; gap: 0.9rem; margin: 1.5rem 0; }
@media (min-width: 44rem) { .tiles { grid-template-columns: repeat(3, 1fr); } }
/*
 * Tokens, not literals — see the note on .coming above.
 *
 * `background: #fff` with no colour of its own was the actual bug: in dark
 * mode the card stayed white while the blurb inherited the light --ink, so
 * the description was near-invisible. Every layer sets its own colour now,
 * so no tile text depends on what it happens to inherit.
 */
.tile { display: block; padding: 1rem 1.1rem; border: 1px solid var(--line); border-radius: var(--radius-lg); text-decoration: none; color: var(--ink); background: var(--surface); }
.tile:hover, .tile:focus-visible { border-color: var(--accent-ink); }
.tile strong { display: block; font-size: 1.05rem; color: var(--accent-ink); }
.tile-blurb { display: block; margin-top: 0.35rem; color: var(--ink); }
.tile-state { display: block; margin-top: 0.6rem; font-size: 0.88rem; color: var(--muted); }
