/* =============================================================================
   Charters & Educational Tours — Portal design system

   Implements "AAG-AET Portal Style Guide.dc.html" (Claude Design project
   "AAG Charters style guide"). One core app, two host-driven themes:

     <html data-theme="aet">              Educational Tours — institutional
     <html data-theme="aag">              AAG umbrella — adventure
     <html data-theme="aag" data-brand="dingos|…">   sub-brand co-branding

   Two rules from the guide that are easy to get wrong:

   1. --color-action is DERIVED, not authored. Any primary that fails 4.5:1
      against white is darkened (×0.92 steps) until it passes, and that value
      becomes buttons and links. That is why every action below carries WHITE
      text — including Adventure Tours, whose orange primary takes BLACK text as
      a background but becomes #A85F03 as an action colour. Never put a label on
      --color-primary; put it on --color-action.

   2. Status colour is NEVER themed. Completed / Pending / Not sent / Expired /
      Awaiting parent keep one fixed set across all nine palettes, so a
      coordinator working both brands reads rows the same way.

   AET's accent (#0EA5A5) reaches only 3.02:1 on white — fills, dots and
   progress bars only. Its action (#0B6E6E) is that hue darkened to 6.05:1.
   ========================================================================== */

/* ── Theme tokens ─────────────────────────────────────────────────────── */

:root,
:root[data-theme="aet"] {
  --color-primary: #111111;
  --color-primary-contrast: #ffffff;
  --color-accent: #0ea5a5;          /* provisional — read off site photography, not a brand token yet */
  --color-action: #0b6e6e;
  --color-action-contrast: #ffffff;

  --color-header-bg: #111111;
  --color-header-fg: #ffffff;
  --color-header-mark-bg: #ffffff;
  --color-header-mark-fg: #111111;

  --color-link: #0b6e6e;
  --color-focus: #0b6e6e;
  --color-focus-ring: rgb(11 110 110 / 20%);

  --font-head: Barlow;
  --font-body: Barlow;
  --weight-section: 700;
  --tracking-section: -0.005em;

  --radius: 10px;
  --radius-sm: 8px;
  --row-padding-y: 16px;            /* teachers checking a list weekly — rows breathe */
}

:root[data-theme="aag"] {
  --color-primary: #244957;
  --color-primary-contrast: #ffffff;
  --color-accent: #84cc16;
  --color-action: #244957;
  --color-action-contrast: #ffffff;

  --color-header-bg: #244957;
  --color-header-fg: #ffffff;
  --color-header-mark-bg: #ffffff;
  --color-header-mark-fg: #244957;

  --color-link: #244957;
  --color-focus: #244957;
  --color-focus-ring: rgb(36 73 87 / 20%);

  --font-head: Archivo;
  --font-body: "Public Sans";
  --weight-section: 600;
  --tracking-section: 0;

  --radius: 12px;
  --radius-sm: 8px;
  --row-padding-y: 13px;            /* operators live in these lists — density is a feature */
}

/* Sub-brand co-branding. --color-action is the primary darkened to clear AA on
   white; the derived values are precomputed here so no runtime maths is needed. */

:root[data-theme="aag"][data-brand="dingos"] {
  --color-primary: #258ecc; --color-primary-contrast: #ffffff; --color-accent: #f59e0b;
  --color-action: #1f78ad;  --color-header-bg: #258ecc; --color-header-fg: #ffffff;
  --color-header-mark-bg: #ffffff; --color-header-mark-fg: #258ecc; --color-link: #1f78ad; --color-focus: #1f78ad;
}
:root[data-theme="aag"][data-brand="adventuretours"] {
  --color-primary: #ff9004; --color-primary-contrast: #000000; --color-accent: #49c0ef;
  --color-action: #a85f03;  --color-header-bg: #ff9004; --color-header-fg: #000000;
  --color-header-mark-bg: #000000; --color-header-mark-fg: #ff9004; --color-link: #a85f03; --color-focus: #a85f03;
}
:root[data-theme="aag"][data-brand="discoverykgari"] {
  --color-primary: #000000; --color-primary-contrast: #ffffff; --color-accent: #ffa007;
  --color-action: #000000;  --color-header-bg: #000000; --color-header-fg: #ffffff;
  --color-header-mark-bg: #ffffff; --color-header-mark-fg: #000000; --color-link: #000000; --color-focus: #000000;
}
:root[data-theme="aag"][data-brand="discoverytours"] {
  --color-primary: #21221d; --color-primary-contrast: #ffffff; --color-accent: #b99a50;
  --color-action: #21221d;  --color-header-bg: #21221d; --color-header-fg: #ffffff;
  --color-header-mark-bg: #ffffff; --color-header-mark-fg: #21221d; --color-link: #21221d; --color-focus: #21221d;
}
:root[data-theme="aag"][data-brand="northernexp"] {
  --color-primary: #9ccb59; --color-primary-contrast: #000000; --color-accent: #99499c;
  --color-action: #5f7b36;  --color-header-bg: #9ccb59; --color-header-fg: #000000;
  --color-header-mark-bg: #000000; --color-header-mark-fg: #9ccb59; --color-link: #5f7b36; --color-focus: #5f7b36;
}
:root[data-theme="aag"][data-brand="territory"] {
  --color-primary: #d3c199; --color-primary-contrast: #375066; --color-accent: #e25f26;
  --color-action: #80755d;  --color-header-bg: #d3c199; --color-header-fg: #375066;
  --color-header-mark-bg: #375066; --color-header-mark-fg: #d3c199; --color-link: #80755d; --color-focus: #80755d;
}
:root[data-theme="aag"][data-brand="wildtasmania"] {
  --color-primary: #1e2a37; --color-primary-contrast: #ffffff; --color-accent: #7e8871;
  --color-action: #1e2a37;  --color-header-bg: #1e2a37; --color-header-fg: #ffffff;
  --color-header-mark-bg: #ffffff; --color-header-mark-fg: #1e2a37; --color-link: #1e2a37; --color-focus: #1e2a37;
}

/* ── Fixed tokens — shared by every theme ─────────────────────────────── */

:root {
  --color-surface: #ffffff;
  --color-page: #f4f6f6;
  --color-surface-sunken: #fafbfb;
  --color-border: #dde2e2;
  --color-border-strong: #c9d1d1;
  --color-rule: #f2f4f4;
  --color-text: #16211f;
  --color-text-muted: #5c6666;
  --color-text-faint: #7a8484;

  /* Status — never themed. */
  --status-complete: #2e7d4f;
  --status-pending: #c8860d;
  --status-expired: #c0362f;
  --status-neutral: #8a9494;

  --space: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;

  --shadow-raised: 0 1px 2px rgb(16 32 30 / 5%), 0 8px 24px rgb(16 32 30 / 7%);
}

/* ── Base ─────────────────────────────────────────────────────────────── */

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

/* Load-bearing: the app toggles every view and panel through the `hidden`
   attribute, and the `display:` rules below would otherwise beat the UA
   stylesheet — leaving the login card and the app shell stacked together. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font-body), system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: var(--color-text);
  background: var(--color-page);
  -webkit-font-smoothing: antialiased;
}

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

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ── Type roles ───────────────────────────────────────────────────────── */

.t-display {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 40px; line-height: 1.08; font-weight: 700; letter-spacing: -0.015em;
}
.t-title {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 28px; line-height: 1.15; font-weight: 700; letter-spacing: -0.01em;
}
.t-section {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 20px; line-height: 1.2;
  font-weight: var(--weight-section); letter-spacing: var(--tracking-section);
}
.t-row { font-size: 14.5px; line-height: 1.4; font-weight: 600; }
.t-meta { font-size: 13px; line-height: 1.5; color: var(--color-text-muted); }

.t-eyebrow {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--color-text-faint);
}

.muted { color: var(--color-text-muted); }
.faint { color: var(--color-text-faint); }

/* ── Buttons — 44px minimum everywhere, desktop included ──────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 44px;
  padding: 12px 20px;
  font-family: inherit; font-size: 14.5px; font-weight: 600; line-height: 1;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: filter 120ms ease, background-color 120ms ease;
}

.btn:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* Disabled flattens a secondary to grey, but a PRIMARY keeps its colour and
   fades instead — see .btn--primary:disabled below. Collapsing both to the same
   grey made every view read as having no action at all, which in Phase 1 is
   half true and half a styling accident: the primary is disabled because the
   Salesforce write does not exist yet, not because it is unimportant. */
.btn:disabled {
  cursor: not-allowed;
  background: #f1f3f3; color: #98a2a2; border-color: #e6eaea;
  filter: none;
}

/* One primary action per view. */
.btn--primary { background: var(--color-action); color: var(--color-action-contrast); }
.btn--primary:not(:disabled):hover { filter: brightness(0.92); }

/* Keeps the action colour so the view still has a visible primary, at 45% so
   it is plainly not pressable. Grey-on-grey lost the hierarchy entirely. */
.btn--primary:disabled {
  background: var(--color-action); color: var(--color-action-contrast);
  border-color: transparent; opacity: 0.45;
}

/* Secondary and ghost stay neutral so a sand or orange primary never has to
   compete with a second coloured button on the same row. */
.btn--secondary { background: var(--color-surface); color: var(--color-text); border-color: var(--color-border-strong); }
.btn--secondary:not(:disabled):hover { background: #f5f7f7; }

.btn--ghost { background: transparent; color: var(--color-link); padding-inline: 12px; }
.btn--ghost:not(:disabled):hover { background: #f1f4f4; }

.btn--sm { min-height: 36px; padding: 8px 14px; font-size: 13.5px; }
.btn--block { width: 100%; }

/* Row-level repeated action — ghost, no box, so four of them don't fight. */
.btn--row {
  min-height: 0; padding: 0; border: 0; background: transparent;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--color-link); cursor: pointer;
}
.btn--row:hover { text-decoration: underline; }
.btn--row:disabled { background: none; color: var(--color-text-faint); text-decoration: none; }

/* ── Fields ───────────────────────────────────────────────────────────── */

.field { display: flex; flex-direction: column; gap: 7px; }
.field__label { font-size: 13px; font-weight: 600; }

.input {
  width: 100%;
  font-family: inherit; font-size: 15px;
  padding: 13px 14px;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}

.input::placeholder { color: #98a2a2; }

.input:focus {
  outline: none;
  border-color: var(--color-focus);
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.input--select { cursor: pointer; }

/* ── Status pills — fixed palette, never themed ───────────────────────── */

.pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px 6px 10px;
  font-size: 12.5px; font-weight: 600; line-height: 1.3;
  border: 1px solid; border-radius: 999px;
  white-space: nowrap;
}

.pill::before {
  content: ""; flex: 0 0 auto;
  width: 7px; height: 7px; border-radius: 999px;
  background: currentColor;
}

.pill--completed { background: #e8f5ec; color: #1b5e33; border-color: #c4e4cf; }
.pill--pending   { background: #fff4e0; color: #8a5a08; border-color: #f3ddb4; }
.pill--notsent   { background: #f1f3f3; color: #4a5555; border-color: #e1e6e6; }
.pill--expired   { background: #fdecea; color: #9b2c22; border-color: #f5cfc9; }
.pill--parent    { background: #eef1fb; color: #33417e; border-color: #d5dcf4; }

/* Delivery, not signature — a separate axis with its own pills (style guide,
   §05). "Link copied" borrows the indigo because reading a link out over the
   phone is the same kind of fact as awaiting someone else: it happened, and
   what follows is out of the coordinator's hands. */
.pill--copied    { background: #eef1fb; color: #33417e; border-color: #d5dcf4; }
.pill--sent      { background: #e8f1f1; color: #12564f; border-color: #c9e2df; }
.pill--reminded  { background: #fff4e0; color: #8a5a08; border-color: #f3ddb4; }

/* Dots carry the stronger status hue rather than the text colour. */
.pill--completed::before { background: var(--status-complete); }
.pill--pending::before   { background: var(--status-pending); }
.pill--notsent::before   { background: var(--status-neutral); }
.pill--expired::before   { background: var(--status-expired); }
.pill--parent::before    { background: #4b5cb8; }
.pill--copied::before    { background: #4b5cb8; }
.pill--sent::before      { background: #1c7a70; }
.pill--reminded::before  { background: var(--status-pending); }

.pill--phase {
  border-color: #e1e6e6; background: #f1f3f3; color: var(--color-text-muted);
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 5px 12px;
}
.pill--phase::before { display: none; }

/* ── Login ────────────────────────────────────────────────────────────── */

.login {
  min-height: 100dvh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: var(--space-6);
}

.login__card {
  width: 100%; max-width: 460px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
}

.login__body { padding: 32px 28px var(--space-8); text-align: center; }

/* Brand artwork, when the theme ships it. The monogram below is the fallback
   for brands whose logo files haven't landed yet. */
.login__logo {
  display: block;
  height: 64px; width: auto;
  max-width: 100%;
  margin: 0 auto 20px;
}

.login__mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 54px; height: 54px; margin-bottom: 20px;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 16px; font-weight: 700;
  background: var(--color-primary); color: var(--color-primary-contrast);
  border-radius: 12px;
}

.login__title {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 22px; font-weight: 700; letter-spacing: -0.01em;
  margin-bottom: var(--space-2);
}

.login__body-text { font-size: 14px; line-height: 1.6; color: var(--color-text-muted); margin-bottom: 22px; }
.login__foot { font-size: 12.5px; line-height: 1.6; color: var(--color-text-faint); margin-top: var(--space-2); }

.login__section {
  padding: 18px 22px;
  background: var(--color-surface-sunken);
  border-top: 1px solid #e8ecec;
}

.login__section-title { font-size: 12px; font-weight: 700; margin-bottom: 10px; }

.login__section--family { text-align: center; }
.login__section--family .family__caption { margin-bottom: var(--space-3); }

/* OTP — six boxes, not one field. */
.otp { display: flex; gap: var(--space-2); }

.otp__box {
  flex: 1; min-width: 0; height: 46px;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 19px; font-weight: 700; text-align: center;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}

.otp__box:focus {
  outline: none;
  border-color: var(--color-focus);
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.stack { display: flex; flex-direction: column; gap: var(--space-3); }
.row { display: flex; align-items: center; gap: var(--space-3); }
.row--split { justify-content: space-between; }

.msg { min-height: 1.25rem; font-size: 13px; line-height: 1.5; color: var(--color-text-muted); }
/* Reserved height only matters once there is a message; an empty one just
   hollows out the bottom of the card. */
.msg:empty { min-height: 0; }
.msg--ok { color: #1b5e33; }
.msg--err { color: #a8231c; }

/* ── App shell ────────────────────────────────────────────────────────── */

.appbar {
  background: var(--color-header-bg);
  color: var(--color-header-fg);
  position: sticky; top: 0; z-index: 30;
}

.appbar__inner {
  max-width: 1180px; margin-inline: auto;
  padding: 16px var(--space-6) 0;
}

.appbar__top { display: flex; align-items: center; gap: 14px; padding-bottom: var(--space-4); }

/* Replaces the monogram AND the text label — the wordmark already says the
   name, so showing both would be the brand twice. Sized for a dark header;
   a theme with a light header needs the on-light variant instead. */
.appbar__logo {
  height: 44px; width: auto;
  flex: 0 0 auto;
  margin-right: auto;
}

.appbar__mark {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: 0 0 auto;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 12px; font-weight: 700;
  background: var(--color-header-mark-bg); color: var(--color-header-mark-fg);
  border-radius: var(--space-2);
}

.appbar__identity { display: flex; align-items: center; gap: 10px; margin-right: auto; min-width: 0; }

.appbar__label { font-size: 15px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Admin is a real capability difference — reaching every booking — so it is
   labelled rather than left to be inferred from the switcher. It sits with the
   avatar because it describes the signed-in person, not the brand: floating
   mid-header it read as part of the masthead. Outlined rather than filled so it
   does not compete with the avatar disc it now sits against. */
.appbar__role {
  flex: 0 0 auto;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px;
  color: var(--color-header-fg);
  border: 1px solid rgb(255 255 255 / 32%);
}
.appbar__avatar {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex: 0 0 auto;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 12px; font-weight: 700;
  background: var(--color-header-mark-bg); color: var(--color-header-mark-fg);
  border-radius: 999px;
}

.appbar__signout {
  background: transparent; border: 0; padding: var(--space-2);
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--color-header-fg); opacity: 0.8; cursor: pointer;
  white-space: nowrap; flex: 0 0 auto;
}
.appbar__signout:hover { opacity: 1; text-decoration: underline; }

/* ── Booking scope bar ────────────────────────────────────────────────
   Both roles can hold several bookings — an admin every one, a coordinator
   however many they run. Everything below this bar (tabs and all tab content)
   is scoped to whatever is selected here, so it sits above the tabs and reads
   as a heading rather than a stray control tucked in the corner. */

/* ── Booking band ──────────────────────────────────────────────────────
   Its own band under the masthead, on a light surface. It was a second row
   inside the dark header, which made the header carry two jobs — who you are,
   and what you are looking at. Those are different questions.

   Sticky under the header so the booking, headcount and progress survive a
   24-row list; --appbar-h is measured in app.js. */

.booking {
  position: sticky; top: var(--appbar-h, 0px); z-index: 20;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.booking__inner {
  max-width: 1180px; margin-inline: auto;
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding: 10px var(--space-6);
}

.booking__eyebrow {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--color-text-faint);
  flex: 0 0 auto;
}

.booking__picker { display: flex; min-width: 0; max-width: 100%; }

.booking__select {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 15px; font-weight: 700; letter-spacing: -0.01em;
  /* Plain max-width, not min(34rem, 100%): the percentage resolves against an
     auto-width parent, so it never bound and the select rendered at its
     intrinsic width (618px), overflowing the row. */
  max-width: 30rem; min-width: 0;
  padding: 5px 30px 5px 10px;
  color: var(--color-text);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-overflow: ellipsis;
}

.booking__select:hover { background: #f1f4f4; }
.booking__select:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

.booking__select option {
  color: var(--color-text); background: var(--color-surface);
  font-size: 15px; font-weight: 500;
}

/* One booking — no control, just the label, matching the select's type. */
.booking__single {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 15px; font-weight: 700; letter-spacing: -0.01em;
  color: var(--color-text);
  min-width: 0; overflow-wrap: anywhere;
}

.booking__meta { font-size: 13px; color: var(--color-text-muted); }

/* Headcount + waiver progress — the number the coordinator is here to act on,
   so it carries the action colour rather than sitting in muted grey. */
.booking__count {
  flex: 0 0 auto;
  font-size: 12.5px; font-weight: 600;
  padding: 3px 10px; border-radius: 999px;
  color: var(--color-action);
  border: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
}

/* Was a full-width tile. The data still is not real and the page should not
   pretend otherwise, but saying so does not need its own band. */
.booking__mock {
  margin-left: auto; flex: 0 0 auto;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px;
  background: #fff4e0; color: #8a5a08; border: 1px solid #f3ddb4;
}



.tabs { display: flex; gap: 26px; }

.tab {
  background: transparent; border: 0;
  border-bottom: 3px solid transparent;
  padding: 0 0 var(--space-3);
  font: inherit; font-size: 14px; font-weight: 600;
  color: var(--color-header-fg);
  opacity: 0.62;
  cursor: pointer;
}

.tab:hover { opacity: 0.85; }
.tab:focus-visible { outline: 2px solid var(--color-header-fg); outline-offset: 3px; }
.tab[aria-selected="true"] { opacity: 1; border-bottom-color: var(--color-header-fg); }

/* ── Shell: left rail + content ───────────────────────────────────────── */

.shell {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

.shell__content { min-width: 0; }

.sidenav {
  display: flex; flex-direction: column; gap: var(--space-6);
  position: sticky; top: calc(var(--space-6) + 96px);
}

.sidenav__group { display: flex; flex-direction: column; gap: 2px; }

.sidenav__grouptitle {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--color-text-faint);
  margin: 0 var(--space-2) var(--space-2);
}

.sidenav__item {
  display: flex; align-items: flex-start; gap: var(--space-2);
  width: 100%;
  padding: 9px var(--space-2) 9px var(--space-3);
  font: inherit; text-align: left;
  background: transparent;
  border: 0; border-radius: var(--radius-sm);
  cursor: pointer;
}

.sidenav__item:hover { background: #f1f4f4; }
.sidenav__item:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.sidenav__item[aria-selected="true"] { background: #eaefef; }

.sidenav__text { display: flex; flex-direction: column; margin-right: auto; min-width: 0; }

.sidenav__label { font-size: 13.5px; font-weight: 600; color: #3d4a48; }
.sidenav__item[aria-selected="true"] .sidenav__label { color: var(--color-text); }

.sidenav__sub {
  font-size: 11px; line-height: 1.4; margin-top: 2px;
  color: #8a9494;
}
.sidenav__item[aria-selected="true"] .sidenav__sub { color: var(--color-text-muted); }

.sidenav__badge {
  flex: 0 0 auto; margin-top: 1px;
  padding: 2px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: #e8ecec; color: var(--color-text-muted);
}
.sidenav__badge:empty { display: none; }

.sidenav__item[aria-selected="true"] .sidenav__badge {
  background: var(--color-action); color: var(--color-action-contrast);
}

/* Panel intro — says what the section is FOR, since Guests and Parents hold
   different records and are easy to confuse. */
.panel__head { margin-bottom: var(--space-4); }

.panel__title {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 20px; line-height: 1.2;
  font-weight: var(--weight-section); letter-spacing: var(--tracking-section);
  margin-bottom: var(--space-2);
}

.panel__blurb {
  font-size: 13.5px; line-height: 1.6;
  color: var(--color-text-muted);
  max-width: 62ch;
}

@media (max-width: 52rem) {
  /* The rail becomes a scrollable strip above the content on narrow screens —
     a 200px column would eat a third of a phone. */
  .shell { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
  /* On a phone the rail becomes a scrollable strip. Group titles and the
     sub-labels are dropped — there is no room, and the labels stand alone. */
  .sidenav {
    position: static;
    flex-direction: row; gap: 0; overflow-x: auto;
    border-bottom: 1px solid var(--color-border);
  }
  .sidenav__group { flex-direction: row; }
  .sidenav__grouptitle { display: none; }
  .sidenav__item {
    width: auto; flex: 0 0 auto;
    border-radius: 0;
    border-bottom: 3px solid transparent;
    padding-inline: var(--space-3);
  }
  .sidenav__item[aria-selected="true"] {
    background: transparent;
    border-bottom-color: var(--color-action);
  }
  .sidenav__sub, .sidenav__badge { display: none; }
}

/* ── Page ─────────────────────────────────────────────────────────────── */

.page { max-width: 1180px; margin-inline: auto; padding: var(--space-6); }

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
}

.card + .card { margin-top: var(--space-4); }

/* ── The one list component ────────────────────────────────────────────
   Guests, Parents and Send waivers are the same table with a different spec
   (style guide §05). They had drifted into three hand-written layouts with
   different column alignment and different action affordances; one component
   is what keeps a coordinator's eye in the same place moving between them. */

.view {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  /* `clip`, NOT `hidden`. Both round off the corners, but `hidden` makes this a
     scroll container, and a scroll container is what a sticky descendant sticks
     to — so the column heads scrolled away with the rest of the table and the
     sticky rule looked like it simply did not work. `clip` does not establish
     one, so the heads stick to the viewport as intended. */
  overflow: clip;
}

.view__head {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 20px 24px;
  border-bottom: 1px solid #edefef;
}

.view__heading { margin-right: auto; min-width: 0; }

.view__title {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 19px; font-weight: 700; letter-spacing: -0.01em;
  margin: 0;
}

.view__sub { font-size: 13px; color: var(--color-text-secondary); margin: 3px 0 0; }

/* Sits outside the rows, in muted type — it explains the list rather than
   labelling any row in it. */
.view__footnote {
  margin: 0; padding: 14px 24px 18px;
  font-size: 12px; line-height: 1.6; color: var(--color-text-faint);
}

.view__empty { padding: 56px 24px; text-align: center; }

/* Filter bar — between the head and the table.

   Deliberately NOT sticky, unlike the column heads above it. Once a filter is
   applied the list is short, which is the whole point; a fourth sticky band
   would cost a row of content on every screen to keep a control you use once
   in reach. */
.filters {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding: 12px 24px;
  background: var(--color-surface-sunken);
  border-bottom: 1px solid #edefef;
}

.filters__field { display: flex; min-width: 0; }
.filters__field .input {
  min-width: 0; width: 15rem; max-width: 100%;
  font-size: 13.5px; padding: 9px 12px;
}

.filters__status {
  font: inherit; font-size: 13.5px;
  padding: 9px 30px 9px 10px;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.filters__status:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* A filtered list that does not say it is filtered reads as a list with people
   missing from it. */
.filters__tally {
  margin-left: auto; flex: 0 0 auto;
  font-size: 12.5px; font-weight: 600; color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 46rem) {
  .filters { padding-inline: var(--space-4); }
  .filters__field, .filters__field .input, .filters__status { width: 100%; }
  .filters__tally { margin-left: 0; }
}

/* --vt-cols comes from the view spec, so the heads and every row below are
   guaranteed to share one grid. */
.vtable__head,
.vtable__row {
  display: grid;
  grid-template-columns: var(--vt-cols, 1.7fr 1.5fr 136px 124px);
  gap: 16px;
}

.vtable__head {
  position: sticky;
  /* Below BOTH sticky bands — the masthead and the booking band. --chrome-h is
     their combined height, measured in app.js rather than assumed, because both
     grow when their contents wrap. */
  top: var(--chrome-h, 0px);
  z-index: 2;
  padding: 10px 24px;
  background: var(--color-surface-sunken);
  border-bottom: 1px solid #edefef;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--color-text-faint);
}

/* Density is the theme's job — AET 16px rows, AAG 13px. */
.vtable__row {
  align-items: center;
  padding: var(--row-padding-y) 24px;
  border-bottom: 1px solid #f2f4f4;
}
.vtable__row:last-child { border-bottom: 0; }

/* A child sits under the parent who signs for them. The guide tints the CHILD
   rows and leaves the parent white — which reads across its five-row mock and
   becomes an undifferentiated wall at eighteen families, where the actual
   question is "where does this family end". So the banding is inverted: the
   parent row is the block header, and a rule above it closes off the family
   before. Children keep the indent. */
.vtable__row--parent {
  background: var(--color-surface-sunken);
  border-top: 1px solid var(--color-border);
}
.vtable__row--parent + .vtable__row--nested { border-top: 0; }
.vtable__row--parent .vtable__name { font-weight: 700; }

.vtable__row--nested .vtable__cell:first-child { padding-left: 26px; }
/* Hairline between siblings; the family's own edges carry the weight. */
.vtable__row--nested { border-bottom-color: #f6f8f8; }

.vtable__cell { min-width: 0; }

.vtable__name {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; row-gap: 4px;
  font-size: 14.5px; font-weight: 600; line-height: 1.3;
  min-width: 0;
}

.vtable__nametext {
  flex: 1 1 auto; min-width: 8ch;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.vtable__sub { font-size: 12.5px; line-height: 1.35; color: var(--color-text-faint); margin-top: 1px; }

.vtable__meta {
  font-size: 13px; color: var(--color-text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.vtable__actions { display: flex; align-items: center; gap: 14px; }

/* Text links, not buttons: at 24 rows a column of bordered buttons is louder
   than the names beside it. */
.rowact {
  padding: 0; border: 0; background: transparent;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--color-link);
  cursor: pointer;
}
.rowact:hover:not([disabled]) { text-decoration: underline; }
.rowact:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; border-radius: 3px; }
.rowact[disabled] { opacity: 0.45; cursor: not-allowed; }

/* Destructive, but NOT red here. One red Remove is a warning; twenty-four of
   them down a list outweigh the status pills beside them and put a destructive
   action at the same visual weight as Edit — easy to mis-tap, and it makes the
   column the loudest thing on the page. Neutral inline; the red belongs on the
   confirmation, where it applies to one named person. */
.rowact--danger { color: var(--color-text-muted); font-weight: 500; }
.rowact--danger:hover:not([disabled]) { color: #a8231c; }

/* Marks a row standing in for someone not yet named — "Student 1 … Student 24"
   blocked out before the school sends the list. */
.chip {
  flex: 0 1 auto; white-space: nowrap;
  padding: 2px 7px; border-radius: 999px;
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  background: #f1f3f3; color: #6b7676;
}

/* Below this the four columns stop being readable side by side. */
@media (max-width: 46rem) {
  .vtable__head { display: none; }
  .vtable__row { grid-template-columns: 1fr; gap: 8px; }
  .vtable__row--nested .vtable__cell:first-child { padding-left: 14px; }
  .vtable__actions { justify-content: flex-start; }
}

/* Empty + placeholder states */
.empty { padding: 64px 22px; text-align: center; }
.empty__title { font-family: var(--font-head), system-ui, sans-serif; font-size: 20px; font-weight: 700; margin-bottom: var(--space-2); }
.empty__body { font-size: 14px; line-height: 1.6; color: var(--color-text-muted); max-width: 46ch; margin: 0 auto; }
.empty__cta { margin-top: var(--space-4); }

.empty--dashed {
  margin: 22px;
  padding: 30px 22px;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius);
}

/* ── Brand family strip ──────────────────────────────────────────────────
   Shown on the AAG entry only — it is the umbrella brand, and the point is to
   show which brands sit under it. The artwork is black monochrome, so this must
   stay on a LIGHT surface; putting it in the themed header would erase it. */

/* Login card only. It was also a footer in the app until it became clear that
   is 200px of chrome under a working list, restating something the coordinator
   accepted at sign-in. */
.family { text-align: center; padding: 0 var(--space-4); width: 100%; }

.family__caption {
  font-family: var(--font-head), system-ui, sans-serif;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--color-text-faint);
  margin-bottom: var(--space-4);
}

/* A white panel carrying the black brand marks. The artwork is black-on-white
   by design, so the panel supplies the white — putting it straight on the page
   tint left the marks looking unmoored. Flex-wrap does the stacking: four up on
   a wide screen, two on a phone, without a breakpoint per count. */
/* Grid, not wrap: marks of differing widths wrap unevenly, whereas fixed
   columns give a clean 5-across that drops to 3 + 2 on a phone.
   Deliberately NOT a card — no surface, border or radius of its own. Two cards
   of equal weight read as peers; this has to read as a footnote. */
.family__panel {
  display: grid;
  /* auto columns + space-between, NOT equal columns. Equal columns centre each
     mark, so a wide mark leaves less air than a narrow one and the gaps read
     as 36 / 30 / 23 / 28. Sizing columns to content and distributing the
     remainder gives one even gap throughout. */
  grid-template-columns: repeat(5, auto);
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4) var(--space-3);
  max-width: 34rem; margin-inline: auto;
}

/* A fixed height with contain keeps wildly different aspect ratios (2:1 through
   to 4:1) reading as one set rather than a jumble. */
.family__logo {
  /* Size comes from height x scale, never from width. max-width is only an
     overflow guard for a narrow cell, and it is paired with object-fit so a
     bind letterboxes rather than squashing the mark out of ratio. */
  --logo-h: 28px;
  height: calc(var(--logo-h) * var(--logo-scale, 1));
  width: auto; max-width: 100%;
  object-fit: contain;
  justify-self: center;
  opacity: 0.8;
}

@media (max-width: 40rem) {
  .family__panel {
    /* Three per row on a phone, with the orphan row CENTRED. Six columns with
       each mark spanning two gives three slots per row; forcing the fourth mark
       to start at column 2 pushes the last pair into columns 2-5, leaving one
       empty column either side.
       `repeat(3, 1fr)` cannot do this: 1fr columns absorb all free space, so
       justify-content has nothing to distribute and items 4-5 sit hard left.
       NOTE: this centring assumes five marks. Revisit if FAMILY changes length. */
    grid-template-columns: repeat(6, 1fr);
    justify-content: stretch;
    column-gap: var(--space-2);
  }
  .family__logo { --logo-h: 24px; grid-column: span 2; }
  .family__logo:nth-child(4) { grid-column: 2 / span 2; }
}

/* ── Narrow screens ───────────────────────────────────────────────────── */

@media (max-width: 40rem) {
  .appbar__inner, .page { padding-inline: var(--space-4); }
  .appbar__logo { height: 32px; }
  .login__logo { height: 52px; }
  .appbar__top { flex-wrap: wrap; }
  .appbar__label { margin-right: 0; }
  .booking__select, .booking__single { font-size: 16px; }
  .view__head, .vtable__row, .view__footnote { padding-inline: var(--space-4); }
}

/* Phase-2 placeholder: the pill sits above the heading. */
.empty__title--spaced { margin-top: var(--space-4); }
