/* MWKC Volunteer Signup
   Club red #940a09 with warm neutrals. No inline styles anywhere: the page
   sends a strict Content-Security-Policy, which blocks style attributes. */

:root {
  --bg: #faf7f6;
  --surface: #ffffff;
  --ink: #23191a;
  --ink-soft: #6b5a5b;
  --line: #e6dcdb;
  --line-strong: #cbbaba;

  --accent: #940a09;
  --accent-dark: #740706;
  --accent-soft: #fbeceb;
  --accent-ring: rgba(148, 10, 9, .28);
  --on-accent: #ffffff;

  --good: #1c6b45;
  --good-soft: #e5f2ea;
  --warn: #8a4a06;
  --warn-soft: #fbeedd;
  --bad: #a3231c;
  --bad-soft: #fbe9e8;

  --radius: 10px;
  --shadow: 0 1px 2px rgba(35, 25, 26, .06), 0 6px 18px rgba(35, 25, 26, .06);
  --shadow-lg: 0 8px 32px rgba(35, 25, 26, .18);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #171110;
    --surface: #211917;
    --ink: #f1e8e7;
    --ink-soft: #b6a4a2;
    --line: #382b29;
    --line-strong: #4e3c3a;

    --accent: #e8756c;
    --accent-dark: #f2938b;
    --accent-soft: #3a1a17;
    --accent-ring: rgba(232, 117, 108, .35);
    --on-accent: #2a0605;

    --good: #6cc596;
    --good-soft: #16332a;
    --warn: #e0a061;
    --warn-soft: #33261a;
    --bad: #ef8a83;
    --bad-soft: #3a1c1a;

    --shadow: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-lg: 0 8px 32px rgba(0, 0, 0, .55);
  }
}

:root[data-theme="dark"] {
  --bg: #171110;
  --surface: #211917;
  --ink: #f1e8e7;
  --ink-soft: #b6a4a2;
  --line: #382b29;
  --line-strong: #4e3c3a;
  --accent: #e8756c;
  --accent-dark: #f2938b;
  --accent-soft: #3a1a17;
  --accent-ring: rgba(232, 117, 108, .35);
  --on-accent: #2a0605;
  --good: #6cc596;
  --good-soft: #16332a;
  --warn: #e0a061;
  --warn-soft: #33261a;
  --bad: #ef8a83;
  --bad-soft: #3a1c1a;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, .55);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.6 "Segoe UI", system-ui, -apple-system, sans-serif;
}

.wrap { max-width: 64rem; margin: 0 auto; padding: 0 1.25rem; }

a { color: var(--accent); }
a:hover { color: var(--accent-dark); }

h1, h2, h3 { line-height: 1.25; text-wrap: balance; margin: 0 0 .5rem; }
h1 { font-size: 1.9rem; }
h2 { font-size: 1.35rem; margin-top: 2rem; }
h3 { font-size: 1.08rem; }
p { margin: 0 0 1rem; }

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

/* --------------------------------------------------------------- header */

.site-header {
  background: var(--surface);
  border-bottom: 3px solid var(--accent);
}

.header-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: center;
  justify-content: space-between;
  padding-top: .8rem;
  padding-bottom: .8rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: .75rem;
  text-decoration: none;
  color: var(--ink);
}
.brand strong { display: block; font-size: 1.05rem; }
.brand small { display: block; color: var(--ink-soft); font-size: .8rem; }

.brand-logo {
  width: 46px;
  height: 46px;
  flex: none;
  object-fit: contain;
  display: block;
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  font-size: .92rem;
}
.site-nav a { text-decoration: none; }
.site-nav a:hover { text-decoration: underline; }

.inline-form { display: inline; margin: 0; }
/* Two of these side by side in a table cell otherwise read as one phrase:
   "Archive Delete". */
.inline-form + .inline-form,
.button + .inline-form { margin-left: .45rem; }

.link-button {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--accent);
  cursor: pointer;
}
.link-button:hover { text-decoration: underline; }

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

main.wrap { padding-top: 2rem; padding-bottom: 3.5rem; }

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--surface);
  padding: 1.5rem 0;
  font-size: .85rem;
  color: var(--ink-soft);
}
.site-footer p { margin: 0; max-width: 46rem; }

.page-head {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 1.5rem;
}
.page-head p { margin: .25rem 0 0; color: var(--ink-soft); }

.breadcrumb { font-size: .85rem; color: var(--ink-soft); margin-bottom: .5rem; }
.lede { font-size: 1.05rem; color: var(--ink-soft); max-width: 42rem; }

/* ---------------------------------------------------------------- toasts */

/* Messages float over the page and fade away; the page never scrolls or
   jumps, so the reader keeps their place. */
.toast-stack {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  width: min(30rem, calc(100vw - 2rem));
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: .85rem 2.4rem .85rem 1.1rem;
  position: relative;
  font-weight: 500;
  opacity: 0;
  transform: scale(.97);
  transition: opacity .5s ease, transform .5s ease;
}
.toast.is-visible { opacity: 1; transform: scale(1); }
.toast.is-leaving { opacity: 0; transform: scale(.97); }

.toast-success { border-left-color: var(--good); }
.toast-error   { border-left-color: var(--bad); }
.toast-info    { border-left-color: var(--accent); }

.toast-close {
  position: absolute;
  top: .3rem;
  right: .4rem;
  background: none;
  border: 0;
  color: var(--ink-soft);
  font-size: 1.1rem;
  line-height: 1;
  padding: .25rem .35rem;
  cursor: pointer;
  border-radius: 4px;
}
.toast-close:hover { color: var(--ink); background: var(--bg); }

/* Fallback for no-JS: render them inline instead. */
.flashes { display: grid; gap: .6rem; margin-bottom: 1.5rem; }
.flash {
  padding: .7rem 1rem;
  border-radius: var(--radius);
  border-left: 3px solid var(--accent);
  background: var(--accent-soft);
}
.flash-success { border-left-color: var(--good); background: var(--good-soft); }
.flash-error   { border-left-color: var(--bad);  background: var(--bad-soft); }

@media (prefers-reduced-motion: reduce) {
  .toast { transition-duration: .01ms; }
}

/* ---------------------------------------------------------------- cards */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.15rem 1.3rem;
  box-shadow: var(--shadow);
}
.card + .card { margin-top: 1rem; }

/* A card carrying the one thing on the page that needs an answer - a waitlist
   place that has come free. Tinted rather than loud: it is good news, not an
   alarm. */
.card-highlight {
  border-color: var(--good);
  border-left-width: 4px;
  background: var(--good-soft);
}
/* The actions strip paints its own background, which would cut the tint in
   half. Here it just needs the dividing rule. */
.card-highlight .card__actions {
  background: transparent;
  border-top-color: var(--good);
}

/* Same shape as card-highlight, but for a state the organiser has to do
   something about rather than one to be pleased with. Draft events use it:
   the event is finished and still invisible, which is easy to miss because
   nothing else on the page looks wrong. */
.card-attention {
  border-color: var(--warn);
  border-left-width: 4px;
  background: var(--warn-soft);
}
.card-attention .card__actions {
  background: transparent;
  border-top-color: var(--warn);
}

.card h3 { margin-top: 0; }

.card-grid {
  display: grid;
  gap: 1.15rem;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  align-items: stretch;
}

/* Inside a grid the gap does the spacing; the stacked-card margin would
   otherwise offset siblings and stop them stretching to equal height. */
.card-grid .card + .card { margin-top: 0; }

/* Event cards are uniform: same height in a row, description clamped, and
   the action pinned to the bottom so buttons line up across the row. */
.event-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.event-card h3 { margin-bottom: .35rem; }

.event-card__meta {
  color: var(--ink-soft);
  font-size: .88rem;
  margin: 0 0 .6rem;
}

.event-card__desc {
  margin: 0 0 .5rem;
  font-size: .92rem;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

.event-card__more {
  align-self: flex-start;
  background: none;
  border: 0;
  padding: 0 0 .5rem;
  font: inherit;
  font-size: .87rem;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
}
.event-card__more:hover { text-decoration: underline; }

.event-card__action { margin-top: auto; padding-top: .75rem; }

/* Full description panel: covers the card so the grid never reflows. The
   text scrolls, the Close button stays put at the bottom, and the text
   fades out as it reaches it. */
.event-card__full {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--radius);
  padding: 1.15rem 1.3rem 0;
  z-index: 2;
  box-shadow: var(--shadow-lg);
}
.event-card__full[hidden] { display: none; }
.event-card__full h4 { margin: 0 0 .5rem; font-size: .95rem; flex: none; }

.event-card__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
}
.event-card__scroll p { font-size: .92rem; margin-bottom: .5rem; }

.event-card__full-foot {
  flex: none;
  position: relative;
  padding: .75rem 0 1rem;
  background: var(--surface);
}
/* The fade the text disappears into, just above the Close button. */
.event-card__full-foot::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 2.5rem;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--surface));
}

.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 0 0 1.5rem;
  padding: 1rem 1.3rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.stat { min-width: 6rem; }
.stat .value {
  display: block;
  font-size: 1.6rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.stat .label {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- roles */

.role {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.2rem;
  box-shadow: var(--shadow);
}
.role + .role { margin-top: .85rem; }
.role.is-full { background: var(--bg); border-style: dashed; }

.role-head {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
}
.role-title { font-size: 1.08rem; font-weight: 600; margin: 0; }
.role-time { color: var(--ink-soft); font-size: .9rem; }
.role-desc { margin: .5rem 0 0; color: var(--ink-soft); }

.role-select { display: flex; gap: .7rem; align-items: flex-start; }
.role-select input[type="checkbox"] { margin-top: .35rem; width: 1.1rem; height: 1.1rem; }

.role-extra {
  margin-top: .9rem;
  padding-top: .9rem;
  border-top: 1px dashed var(--line-strong);
}
.role-extra[hidden] { display: none; }

/* Event web page link shown to volunteers, sitting midway between the
   event description and the first heading of the signup form. */
.event-link {
  margin: 2rem 0;
  padding: .75rem 1rem;
  background: var(--accent-soft);
  border-radius: var(--radius);
  border-left: 3px solid var(--accent);
}
.event-link p { margin: 0 0 .25rem; font-size: .92rem; }
.event-link a { font-weight: 600; overflow-wrap: anywhere; }

/* Cancels a heading's own top margin so the gap above it is set purely by
   the preceding block - that is what makes the link panel equidistant. */
.section-start { margin-top: 0; }

/* Copyable link row, used for the volunteer signup address. */
.copy-row {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}
.copy-row code {
  flex: 1 1 18rem;
  min-width: 0;
  padding: .5rem .7rem;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: Consolas, "SF Mono", Menlo, monospace;
  font-size: .88rem;
  overflow-wrap: anywhere;
}
.copy-button { flex: none; }
.copy-button .copy-icon { font-size: 1rem; line-height: 1; }

/* ------------------------------------------------------------- tooltips */

.has-tip { position: relative; display: inline-flex; }

.has-tip .tip {
  position: absolute;
  bottom: calc(100% + .5rem);
  left: 50%;
  transform: translateX(-50%) translateY(.25rem);
  z-index: 70;
  width: max-content;
  max-width: 20rem;
  padding: .55rem .75rem;
  background: var(--ink);
  color: var(--bg);
  border-radius: 6px;
  font-size: .82rem;
  font-weight: 400;
  line-height: 1.4;
  white-space: normal;
  text-align: left;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease, visibility .18s;
}
.has-tip .tip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: .35rem solid transparent;
  border-top-color: var(--ink);
}
.has-tip:hover .tip,
.has-tip:focus-within .tip {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .has-tip .tip { transition: none; }
}

/* --------------------------------------------------------------- badges */

.badge {
  display: inline-block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: .18rem .5rem;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  white-space: nowrap;
}
.badge-good { background: var(--good-soft); color: var(--good); }
.badge-warn { background: var(--warn-soft); color: var(--warn); }
.badge-bad  { background: var(--bad-soft);  color: var(--bad); }
.badge-muted { background: var(--bg); color: var(--ink-soft); border: 1px solid var(--line); }

.badge-row { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .5rem; }

/* ---------------------------------------------------------------- forms */

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

/* One height for every control, so rows of fields line up. Left to
   themselves, text, number, date and select each render differently. */
input[type="text"], input[type="email"], input[type="tel"], input[type="date"],
input[type="url"], input[type="number"], select, textarea, .tp__trigger {
  width: 100%;
  min-height: 2.75rem;
  padding: .5rem .7rem;
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .95rem;
  line-height: 1.4;
}
textarea { min-height: 6rem; resize: vertical; }

input:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: var(--accent);
  outline: 3px solid var(--accent-ring);
  outline-offset: 0;
}

.field { margin-bottom: 1.1rem; }
.field .hint { font-size: .85rem; color: var(--ink-soft); margin: .3rem 0 0; font-weight: 400; }

.field-row {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.check {
  display: flex;
  gap: .6rem;
  align-items: flex-start;
  font-weight: 400;
  margin-bottom: .6rem;
}
.check input { margin-top: .3rem; width: 1.05rem; height: 1.05rem; flex: none; }

fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.2rem;
  margin: 0 0 1.2rem;
}
legend { font-weight: 700; padding: 0 .4rem; }

/* Buttons follow one hierarchy across the whole app:
     .button            filled club red - THE action of a panel or page
     .button-secondary  outlined        - supporting actions, navigation
     .button-danger     outlined red    - destructive, recessive until chosen
     .link-button       plain text      - minor or reversible actions
   Every button is the same height; only .button-small differs, and it is
   used only inside dense table rows. */

button, .button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  min-height: 2.5rem;
  padding: 0 1.1rem;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--accent);
  color: var(--on-accent);
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
}
button:hover, .button:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: var(--on-accent);
}

.button-secondary { background: var(--surface); color: var(--accent); }
.button-secondary:hover { background: var(--accent-soft); color: var(--accent-dark); }

/* Three weights that must all be told apart at a glance: filled club red is
   the main action, plain outlined is supporting, and destructive is tinted.
   Solid red made a delete shout as loudly as the main action beside it;
   plain outlined made it indistinguishable from Cancel, since the club red
   and the warning red are close. The tint separates it from both. */
.button-danger {
  background: var(--bad-soft);
  border-color: var(--bad);
  color: var(--bad);
}
.button-danger:hover { background: var(--bad); border-color: var(--bad); color: #fff; }

/* Table-row scale only. */
.button-small {
  min-height: 2rem;
  padding: 0 .7rem;
  font-size: .85rem;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  align-items: center;
  margin-top: 1.2rem;
}

/* The standard place for a panel's actions: inside it, along the bottom,
   separated by a rule. Every card that acts on something uses this. */
.card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
  align-items: center;
  margin: 1.25rem -1.3rem -1.15rem;
  padding: .9rem 1.3rem;
  border-top: 1px solid var(--line);
  background: var(--bg);
  border-radius: 0 0 var(--radius) var(--radius);
}
.card__actions .note { color: var(--ink-soft); font-size: .85rem; }
.card__actions form { margin: 0; }

/* Page-level actions sitting beside a heading. */
.page-head .actions { margin-top: 0; }

/* ------------------------------------------------------------- dropdown */

.dropdown { position: relative; display: inline-block; }

.dropdown__toggle::after {
  content: "";
  display: inline-block;
  margin-left: .45rem;
  border: .3rem solid transparent;
  border-top-color: currentColor;
  transform: translateY(.15rem);
}

.dropdown__menu {
  position: absolute;
  top: calc(100% + .35rem);
  right: 0;
  min-width: 11rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: .3rem;
  z-index: 40;
  display: grid;
  gap: .15rem;
}
.dropdown__menu[hidden] { display: none; }

.dropdown__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: .5rem .7rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}
.dropdown__item:hover, .dropdown__item:focus-visible {
  background: var(--accent-soft);
  color: var(--accent);
}
.dropdown__item small { display: block; color: var(--ink-soft); font-size: .78rem; font-weight: 400; }

/* ---------------------------------------------------- time wheel picker */

/* Replaces the native time input. Values are chosen by scrolling each
   column so the wanted number sits inside the centred window. */
.tp { position: relative; }

.tp__native {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
  margin: 0;
  border: 0;
  padding: 0;
}

.tp__trigger {
  text-align: left;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  white-space: nowrap;
}
/* It is a <button>, so without this it picks up the filled button hover and
   turns solid red. It must keep reading as a form control. */
.tp__trigger:hover,
.tp__trigger[aria-expanded="true"] {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--accent);
}
.tp__trigger[aria-expanded="true"] {
  outline: 3px solid var(--accent-ring);
}
.tp__trigger.is-empty { color: var(--ink-soft); }

/* A drawn clock rather than an emoji: emoji render at the mercy of the
   platform font and were too faint to read at this size. */
.tp__icon {
  color: var(--accent);
  flex: none;
  display: inline-flex;
  align-items: center;
}
.tp__icon svg { display: block; }
.tp__trigger:hover .tp__icon { color: var(--accent-dark); }

.tp__panel {
  position: absolute;
  z-index: 60;
  top: calc(100% + .4rem);
  left: 0;
  min-width: 17rem;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  padding: .75rem;
}
.tp__panel[hidden] { display: none; }
.tp__panel.is-above { top: auto; bottom: calc(100% + .4rem); }

/* Column headings sit outside the wheel area. When they were inside it, the
   centre window was measured against label + column and ended up sitting
   high, so the chosen time appeared to rest on the bottom border. */
.tp__labels {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: .25rem;
  margin-bottom: .3rem;
}

.tp__wheels {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: .25rem;
}

/* The window the chosen time scrolls into. Its height matches one option
   exactly, so the centred option sits squarely between the borders. */
.tp__window {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2.5rem;
  margin-top: -1.25rem;
  border-top: 1px solid var(--accent);
  border-bottom: 1px solid var(--accent);
  background: var(--accent-soft);
  border-radius: 6px;
  pointer-events: none;
}

.tp__col {
  height: 12.5rem;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
  position: relative;
  z-index: 1;
  /* Fade the ends so it reads as a wheel. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 22%, #000 78%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 22%, #000 78%, transparent 100%);
}
.tp__col::-webkit-scrollbar { width: 0; height: 0; }
.tp__col:focus-visible { outline: 3px solid var(--accent-ring); border-radius: 6px; }

/* Half the column height minus half an option, so the first and last
   options can still reach the centre window. */
.tp__pad { height: 5rem; }

.tp__opt {
  height: 2.5rem;
  scroll-snap-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  cursor: pointer;
  user-select: none;
  border-radius: 6px;
  transition: color .18s ease, font-weight .18s ease, transform .18s ease;
}
.tp__opt:hover { color: var(--ink); }
.tp__opt.is-selected {
  color: var(--accent);
  font-weight: 700;
  transform: scale(1.06);
}

.tp__label {
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--ink-soft);
  text-align: center;
  font-weight: 600;
  margin-bottom: .25rem;
}

.tp__foot {
  display: flex;
  gap: .5rem;
  align-items: center;
  justify-content: space-between;
  margin-top: .7rem;
  padding-top: .7rem;
  border-top: 1px solid var(--line);
}
.tp__preview { font-weight: 700; font-variant-numeric: tabular-nums; }

/* While a column is being dragged the cursor should say so, and the
   browser must not start a text selection instead. */
.tp__col.is-dragging { cursor: grabbing; }
.tp__col.is-dragging .tp__opt { cursor: grabbing; }

@media (prefers-reduced-motion: reduce) {
  .tp__col { scroll-behavior: auto; }
  .tp__opt { transition: none; }
}

/* --------------------------------------------------------------- tables */

.table-wrap { overflow-x: auto; }

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  font-size: .92rem;
}
th, td {
  text-align: left;
  padding: .55rem .7rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-soft);
  border-bottom: 2px solid var(--line-strong);
}
tbody tr:hover { background: var(--accent-soft); }
td.numeric { font-variant-numeric: tabular-nums; text-align: right; }

/* Each role renders its own table, so without fixed widths every role's
   columns line up differently. Fixed layout plus explicit widths makes the
   whole schedule read as one grid, at any viewport. */
.schedule-table,
.runsheet-table {
  table-layout: fixed;
}
.schedule-table th, .schedule-table td,
.runsheet-table th, .runsheet-table td {
  overflow-wrap: anywhere;
}

/* Nothing inside these tables may hold a column open: a badge is long
   enough to spill right across its neighbour. */
.schedule-table .badge,
.runsheet-table .badge { white-space: normal; }

.schedule-table th:nth-child(1), .schedule-table td:nth-child(1) { width: 19%; }
.schedule-table th:nth-child(2), .schedule-table td:nth-child(2) { width: 21%; }
.schedule-table th:nth-child(3), .schedule-table td:nth-child(3) { width: 12%; }
.schedule-table th:nth-child(4), .schedule-table td:nth-child(4) { width: 25%; }
.schedule-table th:nth-child(5), .schedule-table td:nth-child(5) { width: 14%; }
.schedule-table th:nth-child(6), .schedule-table td:nth-child(6) { width: 9%; }

.runsheet-table th:nth-child(1), .runsheet-table td:nth-child(1) { width: 2.6rem; }
.runsheet-table th:nth-child(2), .runsheet-table td:nth-child(2) { width: 24%; }
.runsheet-table th:nth-child(3), .runsheet-table td:nth-child(3) { width: 19%; }
.runsheet-table th:nth-child(4), .runsheet-table td:nth-child(4) { width: 20%; }
.runsheet-table th:nth-child(5), .runsheet-table td:nth-child(5) { width: 32%; }

/* A minimum width at every viewport, not only on phones: below it the
   wrapper scrolls. Without this the columns keep shrinking until phone
   numbers and times — which must not wrap — spill across their neighbours,
   and the scrollbar only arrives long after the table stopped being
   readable. */
.schedule-table { min-width: 44rem; }
.runsheet-table { min-width: 38rem; }

/* Fields edited straight in a table row. Deliberately quiet until they are
   used: a full form control in every row would turn the table into a wall of
   boxes. The full-size control rules above are overridden here. */
input.inline-input {
  width: 100%;
  min-height: 1.9rem;
  padding: .15rem .35rem;
  font-size: .88rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: inherit;
  font-family: inherit;
}
input.inline-input:hover { border-color: var(--line); background: var(--surface); }
input.inline-input:focus,
input.inline-input:focus-visible {
  border-color: var(--accent);
  background: var(--surface);
  outline: 2px solid var(--accent-ring);
  outline-offset: 0;
}
.inline-input::placeholder { color: var(--ink-soft); opacity: .65; }

.when-cell { white-space: nowrap; }
.when-cell input.inline-input { width: 4.9rem; display: inline-block; }
.when-dash { color: var(--ink-soft); margin: 0 -.1rem; }

/* The screen-reader-only list inside is absolutely positioned; without a
   positioned cell to sit in it takes its static position inside the
   horizontally scrolled table and stretches the whole page sideways. */
.filled-cell { position: relative; }

.filled-count { display: inline-flex; align-items: center; gap: .15rem; white-space: nowrap; }
input.inline-number { width: 3.2rem; text-align: center; }

/* The Save button is the fallback for a browser with scripting turned off;
   with it on, the row saves itself and says so here. */
.inline-form button[hidden] { display: none; }

/* Saving happens quietly; what happened is said in the floating message
   stack, which is visible wherever the reader is looking. */

/* Read to a screen reader, never shown: the visible version is the floating
   panel built in app.js. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The filled figure lists who is in the role when hovered. The panel is
   attached to the page rather than the cell, because the table scrolls
   inside its wrapper and would clip anything positioned within it. */
.filled-figure {
  cursor: help;
  border-bottom: 1px dotted var(--line-strong);
}
.filled-figure:hover,
.filled-figure:focus-visible { border-bottom-color: var(--accent); }

.floating-tip {
  position: fixed;
  z-index: 80;
  max-width: 18rem;
  padding: .55rem .75rem;
  background: var(--ink);
  color: var(--bg);
  border-radius: 6px;
  font-size: .82rem;
  font-weight: 400;
  line-height: 1.45;
  text-align: left;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transition: opacity .15s ease;
  pointer-events: none;
}
.floating-tip.is-visible { opacity: 1; }
.floating-tip strong { display: block; margin-bottom: .15rem; }
.floating-tip ul { margin: 0; padding-left: 1.1rem; }

@media (prefers-reduced-motion: reduce) {
  .floating-tip { transition: none; }
}

/* Event details, shown as a summary until Edit is pressed. */
.summary { margin: 0; display: grid; gap: .9rem 2rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.summary dt { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-soft); font-weight: 700; }
.summary dd { margin: .15rem 0 0; }

/* A long description otherwise makes its row as tall as itself and leaves
   the cells beside it empty. It gets the full width and its own row. */
.summary-full { grid-column: 1 / -1; }

/* The master roles list. Same shape as an event's roles table, without the
   columns that only make sense once a role belongs to an event. */
.roles-table { table-layout: fixed; min-width: 40rem; }
.roles-table th, .roles-table td { overflow-wrap: anywhere; }
.roles-table th:nth-child(1), .roles-table td:nth-child(1) { width: 32%; }
.roles-table th:nth-child(2), .roles-table td:nth-child(2) { width: 24%; }
.roles-table th:nth-child(3), .roles-table td:nth-child(3) { width: 12%; }
.roles-table th:nth-child(4), .roles-table td:nth-child(4) { width: 14%; }
.roles-table th:nth-child(5), .roles-table td:nth-child(5) { width: 18%; }
.roles-table .badge { white-space: normal; }

/* Same table, different content: the requirement wording needs the room and
   the badges need enough not to break across lines. */
.requirements-table th:nth-child(1), .requirements-table td:nth-child(1) { width: 22%; }
.requirements-table th:nth-child(2), .requirements-table td:nth-child(2) { width: 32%; }
.requirements-table th:nth-child(3), .requirements-table td:nth-child(3) { width: 17%; }
.requirements-table th:nth-child(4), .requirements-table td:nth-child(4) { width: 12%; }
.requirements-table th:nth-child(5), .requirements-table td:nth-child(5) { width: 17%; }

/* Same table again, six columns this time: an email needs the room a
   requirement's wording needed. */
.users-table { min-width: 48rem; }
.users-table th:nth-child(1), .users-table td:nth-child(1) { width: 22%; }
.users-table th:nth-child(2), .users-table td:nth-child(2) { width: 22%; }
.users-table th:nth-child(3), .users-table td:nth-child(3) { width: 11%; }
.users-table th:nth-child(4), .users-table td:nth-child(4) { width: 16%; }
.users-table th:nth-child(5), .users-table td:nth-child(5) { width: 13%; }
.users-table th:nth-child(6), .users-table td:nth-child(6) { width: 16%; }

/* "Event organiser" broken over two lines makes every row as tall as the
   longest badge. The table already scrolls in its wrapper when it has to. */
.users-table td:nth-child(4) .badge { white-space: nowrap; }

/* The seeding-order table underneath carries no header row, so its columns
   are sized by content instead. */
.card .roles-table { min-width: 0; table-layout: auto; }

/* Volunteer schedule: anyone still waiting has an editable status, so
   promoting them needs no second button competing with Remove for room in
   the row. */
.status-form { display: flex; flex-wrap: wrap; gap: .35rem; }
.status-form button[hidden] { display: none; }
.status-select {
  min-height: 2rem;
  padding: .1rem .45rem;
  font-size: .82rem;
  font-weight: 600;
}
.status-select.is-waiting {
  background: var(--warn-soft);
  border-color: var(--warn);
}

/* Reorder arrows in the roles list. */
.order-cell { white-space: nowrap; display: flex; gap: .2rem; }
.order-button {
  min-height: 1.9rem;
  width: 1.9rem;
  padding: 0;
  font-size: .8rem;
  line-height: 1;
  background: var(--surface);
  color: var(--accent);
  border: 1px solid var(--line-strong);
}
.order-button:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-dark); }
.order-button:disabled { opacity: .35; cursor: default; }

/* ---------------------------------------------------------------- misc */

.empty {
  padding: 2.5rem 1.5rem;
  text-align: center;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
}

.clash-warning {
  margin-top: 1rem;
  padding: .8rem 1rem;
  border-radius: var(--radius);
  background: var(--warn-soft);
  border-left: 3px solid var(--warn);
  font-size: .92rem;
}
.clash-warning[hidden] { display: none; }
.clash-warning strong { display: block; }

.muted { color: var(--ink-soft); }
.small { font-size: .87rem; }
.nowrap { white-space: nowrap; }
.divider { border: 0; border-top: 1px solid var(--line); margin: 2rem 0; }
.divider-tight { margin: 1.2rem 0; }

/* Spam trap: kept out of sight and out of the tab order. A CSP blocks
   style attributes, so this must be a class, not an inline style. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ------------------------------------------------------------ utilities */

.m-0 { margin: 0; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.mt-xs { margin-top: .4rem; }
.mb-xs { margin-bottom: .4rem; }
.mt-sm { margin-top: .8rem; }
.mb-sm { margin-bottom: .8rem; }
.mt-md { margin-top: 1rem; }
.my-md { margin: 1rem 0; }
.mt-lg { margin-top: 2rem; }
.mb-md { margin-bottom: 1rem; }
.pull-up { margin-top: -.55rem; }
.d-block { display: block; }
.fw-normal { font-weight: 400; }
.flex-1 { flex: 1; }
.w-tick { width: 2.5rem; }
.w-xs { max-width: 7rem; }
.w-sm { max-width: 8rem; }
.narrow-page { max-width: 30rem; margin: 2rem auto; }

/* ---------------------------------------------------------------- print */

/* Printed-page margins.
   @page alone is not enough: if the print dialog's own margin setting is
   "None" it wins, and the text runs to the paper edge. So the page box asks
   for a modest margin AND the content carries its own padding, which no
   print setting can remove. */
@page { margin: 12mm; }



/* ------------------------------------------------------- email previews */

/* The body is shown as it will arrive: fixed width, wrapped at the same
   place the sender wrapped it, so a line that will look wrong in a mail
   client looks wrong here too. */
.email-index {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem .5rem;
  margin: 0 0 1.25rem;
}
.email-index a {
  padding: .25rem .6rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font-size: .85rem;
  text-decoration: none;
}
.email-index a:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.email-subject {
  margin: 0 0 .75rem;
  padding-bottom: .6rem;
  border-bottom: 1px solid var(--line);
}
.email-subject__label {
  display: inline-block;
  min-width: 4.5rem;
  font-size: .78rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.email-body {
  margin: 0;
  padding: 1rem 1.1rem;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-family: ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: .85rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------- poster */

/* One sheet for the clubhouse noticeboard. Somebody reads this standing up,
   from a metre away, so the hierarchy is much steeper than anywhere else in
   the app: headline, square, address, and only then the detail. */

.poster {
  max-width: 44rem;
  margin: 0 auto;
  text-align: center;
  color: #000;
}

.poster__head { margin-bottom: 1.5rem; }
.poster__logo { display: block; margin: 0 auto .5rem; }
.poster__club {
  margin: 0;
  font-size: .95rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 700;
}

.poster__title {
  margin: 0 0 1.5rem;
  font-size: 3rem;
  line-height: 1.05;
  text-wrap: balance;
}

.poster__event {
  margin: 0 0 .35rem;
  font-size: 1.6rem;
  font-weight: 700;
}
.poster__when {
  margin: 0 0 1.75rem;
  font-size: 1.15rem;
  line-height: 1.5;
}

.poster__qr { margin: 0 0 1rem; }
.poster__qr svg {
  display: block;
  margin: 0 auto;
  width: 15rem;
  height: auto;
}

.poster__cta {
  margin: 0 0 .3rem;
  font-size: 1.25rem;
  font-weight: 700;
}
.poster__url {
  margin: 0 0 2rem;
  font-size: 1.05rem;
  word-break: break-all;
  color: var(--accent);
}

.poster__roles {
  text-align: left;
  border-top: 2px solid #000;
  padding-top: 1rem;
  margin-bottom: 1.5rem;
}
.poster__roles-head { margin: 0 0 .5rem; font-weight: 700; }
.poster__roles ul { margin: 0; padding-left: 1.2rem; }
.poster__roles li { margin-bottom: .3rem; }
.poster__role-time { color: #444; }
.poster__role-need { font-weight: 700; }

.poster__foot {
  margin: 0;
  font-size: .9rem;
  color: #444;
}

/* One sheet, and the QR must not shrink below the size a phone camera can
   read comfortably at arm's length. */
@media print {
  .poster { max-width: none; }
  .poster__title { font-size: 34pt; }
  .poster__event { font-size: 18pt; }
  .poster__when { font-size: 13pt; }
  .poster__qr svg { width: 62mm; }
  .poster__cta { font-size: 14pt; }
  .poster__roles { break-inside: avoid; }
}

.print-page { background: #fff; color: #000; }
.print-actions { margin: 1rem 0; }

/* On screen the run sheet has no site header, so give it breathing room.
   The print rules below replace this with the printed-page inset. */
.print-page > .wrap { padding-top: 2rem; padding-bottom: 3rem; }

@media print {
  .no-print, .site-header, .site-footer, .toast-stack { display: none !important; }

  html, body {
    background: #fff;
    color: #000;
    font-size: 11pt;
    margin: 0;
    padding: 0;
  }

  /* The guaranteed inset. */
  .wrap {
    max-width: none;
    margin: 0;
    padding: 10mm 12mm !important;
  }

  .table-wrap { overflow: visible; }
  .schedule-table, .runsheet-table { min-width: 0; }

  table { font-size: 10pt; }
  th, td { border-bottom: 1px solid #999; }
  tbody tr:hover { background: transparent; }
  h2 { break-after: avoid; }
  tr { break-inside: avoid; }
  a { color: #000; text-decoration: none; }
}
