/* Pet Project Foundation — volunteer scheduling
   Brand palette pulled from petprojectfoundation.org:
   navy #14446C, dark #083860, light accent #CCE8F4, neutral grays. */

:root {
  --navy: #14446c;
  --navy-dark: #083860;
  --navy-900: #0a2338;
  --accent: #cce8f4;
  --accent-strong: #7fc4e6;
  --ink: #1f2933;
  --muted: #6b7280;
  --line: #e3e8ee;
  --bg: #f4f7fa;
  --card: #ffffff;
  --ok: #2e7d55;
  --ok-bg: #e6f4ec;
  --warn: #b45309;
  --warn-bg: #fdf1e3;
  --danger: #b3261e;
  --danger-bg: #fbe9e7;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(10, 35, 56, .06), 0 8px 24px rgba(10, 35, 56, .06);
  --font-body: "Red Hat Text", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-head: "Roboto Slab", Georgia, serif;
  /* The palette is light-only. Declaring it stops mobile browsers in dark mode
     from giving unstyled controls (file inputs, checkboxes, date/time pickers)
     dark chrome against our forced-white fields. */
  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.5;
}

h1, h2, h3, h4 { font-family: var(--font-head); color: var(--navy-900); margin: 0 0 .4em; }
a { color: var(--navy); }

/* ---------- Layout ---------- */
.site-header {
  background: var(--navy);
  color: #fff;
  border-bottom: 4px solid var(--accent-strong);
}
.site-header .bar {
  max-width: 1180px; margin: 0 auto; padding: .6rem 1.25rem;
  display: flex; align-items: center; gap: 1.5rem;
  /* .nav-panel anchors to this box on mobile (position:absolute, top:100%) so
     the dropdown spans the header's full width regardless of .nav's own
     (much narrower, hamburger-only) box. */
  position: relative;
}
.brand { display: flex; align-items: center; gap: .75rem; min-width: 0; }
.brand img { height: 46px; width: auto; background: #fff; padding: 6px 10px; border-radius: 10px; }
.brand .title { font-family: var(--font-head); font-weight: 600; font-size: 1.05rem; line-height: 1.1; }
.brand .title small { display: block; font-family: var(--font-body); font-weight: 400; opacity: .8; font-size: .72rem; letter-spacing: .04em; text-transform: uppercase; }
/* ── Header nav ── */
/* .nav is just a row holding the (mobile-only) hamburger toggle and the
   panel; the panel carries the layout .nav used to have directly, so that
   collapsing it on mobile doesn't disturb the desktop flex column below. */
.nav {
  display: flex; align-items: center; gap: .3rem;
  margin-left: auto; min-width: 0;
}
.nav-panel {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 0; min-width: 0;
}
/* Hamburger toggle — hidden on desktop; shown only under the mobile query. */
.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex-shrink: 0;
  background: none; border: none; border-radius: 8px; cursor: pointer; padding: 0;
}
.nav-toggle:hover { background: rgba(255,255,255,.14); }
.nav-toggle-icon { display: flex; flex-direction: column; justify-content: center; gap: 5px; width: 22px; height: 16px; }
.nav-toggle-icon span {
  display: block; height: 2px; width: 100%; background: #fff; border-radius: 2px;
  transition: transform .15s ease, opacity .15s ease;
}
/* Animate the bars into an X while the panel is open. */
.nav-toggle[aria-expanded="true"] .nav-toggle-icon span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-icon span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-icon span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* nav-main: one flex row — scrollable links + static right section */
.nav-main {
  display: flex; align-items: center;
}
/* Links wrap rather than scroll. A hidden-scrollbar strip silently swallowed
   whole nav items (Reports/Availability were unreachable at 375px) with no
   affordance that anything was there. Wrapping keeps every item reachable;
   .nav-user sits on its own row so Sign out never moves. */
.nav-links {
  display: flex; align-items: center; gap: .15rem;
  flex-wrap: wrap; justify-content: flex-end; row-gap: .1rem;
  min-width: 0;
}
/* nav-static: Coordinate dropdown + Admin — never scroll, never clip */
.nav-static {
  display: flex; align-items: center; gap: .15rem; flex-shrink: 0;
}
.nav-user {
  display: flex; align-items: center; gap: .5rem;
  padding-top: .1rem; justify-content: flex-end;
}
.nav a {
  color: #fff; text-decoration: none; padding: .38rem .72rem; border-radius: 999px;
  font-size: .88rem; opacity: .92; white-space: nowrap; flex-shrink: 0;
}
.nav a:hover, .nav a.active { background: rgba(255,255,255,.16); opacity: 1; }
/* The signed-in name is the way into "My profile", so it is an anchor now.
   Keep it looking like the label it was — inheriting the header's colour, no
   underline until hovered — rather than a stray blue link in the bar. */
.nav .who { opacity: .75; font-size: .8rem; white-space: nowrap;
            color: inherit; text-decoration: none; }
.nav a.who:hover, .nav a.who:focus-visible { opacity: 1; text-decoration: underline; }

/* Sign-out icon button — replaces a text label everywhere (mobile + desktop)
   so it reads as a distinct, compact action next to the volunteer's name. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; min-width: 44px; min-height: 44px;
  padding: 0; border-radius: 999px; border: 1px solid transparent;
  background: #fff; color: var(--navy); cursor: pointer;
  transition: filter .12s ease;
}
.icon-btn:hover { filter: brightness(.96); }
.icon-btn svg { width: 18px; height: 18px; display: block; }

/* Coordinate dropdown — click-toggled via JS, lives in nav-static (no overflow clip) */
.nav-dropdown { position: relative; }
.nav-drop-btn {
  background: none; border: none; cursor: pointer;
  color: #fff; padding: .38rem .72rem; border-radius: 999px;
  font-size: .88rem; opacity: .92; font-family: inherit; white-space: nowrap;
}
.nav-drop-btn:hover { background: rgba(255,255,255,.16); opacity: 1; }
.nav-drop-menu {
  display: none; position: absolute; right: 0; top: calc(100% + .4rem);
  background: var(--navy-dark); border-radius: 8px; min-width: 180px;
  box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 200; overflow: hidden;
}
.nav-drop-menu.open { display: block; }
.nav-drop-menu a {
  display: block; border-radius: 0; padding: .6rem 1rem;
  border-bottom: 1px solid rgba(255,255,255,.08); font-size: .88rem;
}
.nav-drop-menu a:last-child { border-bottom: none; }

.main { max-width: 1180px; margin: 1.6rem auto; padding: 0 1.25rem; }
.page-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.page-head p { color: var(--muted); margin: .15rem 0 0; }

/* ---------- Cards ---------- */
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.card .card-body { padding: 1.1rem 1.25rem; }
.grid { display: grid; gap: 1.1rem; }
@media (min-width: 780px) { .grid.cols-2 { grid-template-columns: 1fr 1fr; } }

/* ---------- Area colour dots ---------- */
/* Base size for every `<span class="dot">`. This used to be declared only
   under .shift-label and .report-table, so a dot anywhere else — the schedule
   buttons and area-membership grid here, plus training and the dashboard —
   collapsed to zero width. It stayed invisible rather than looking broken,
   but its parent's flex `gap` still reserved space beside it, which read as
   the label sitting slightly off-centre. */
.dot {
  display: inline-block; flex: none;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent-strong);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: .4rem; cursor: pointer;
  font: inherit; font-weight: 600; font-size: .9rem;
  padding: .5rem .95rem; border-radius: 999px; border: 1px solid transparent;
  text-decoration: none; transition: filter .12s ease, background .12s ease;
}
.btn:disabled, .btn.is-disabled { opacity: .5; cursor: not-allowed; }
.btn-primary { background: var(--navy); color: #fff; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-outline { background: #fff; color: var(--navy); border-color: var(--navy); }
.btn-outline:hover { background: var(--accent); }
.btn-danger { background: var(--danger-bg); color: var(--danger); border-color: #f0c5c0; }
.btn-danger:hover { filter: brightness(.98); }
.btn-sm { padding: .32rem .7rem; font-size: .82rem; }

/* ---------- Schedule grid ---------- */
.week { display: grid; gap: .85rem; grid-template-columns: 1fr; }
@media (min-width: 720px) { .week { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .week { grid-template-columns: repeat(3, 1fr); } }

.day { border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); overflow: hidden; box-shadow: var(--shadow); }
.day.is-today { outline: 2px solid var(--accent-strong); }
.day-head { padding: .55rem .85rem; background: var(--navy-900); color: #fff; display: flex; justify-content: space-between; align-items: baseline; }
.day-head .dow { font-family: var(--font-head); font-size: 1rem; }
.day-head .date { opacity: .75; font-size: .82rem; }
.day-body { padding: .7rem .85rem; display: grid; gap: .7rem; }

.shift { border: 1px solid var(--line); border-radius: 12px; padding: .6rem .7rem; }
.shift.cancelled { background: repeating-linear-gradient(45deg,#faf1f0,#faf1f0 8px,#fff 8px,#fff 16px); }
.shift-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .45rem; }
.shift-label { display: inline-flex; align-items: center; gap: .4rem; font-weight: 600; }
.shift-label .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--accent-strong); }
.shift-time { color: var(--muted); font-size: .82rem; }
.shift-oneoff { font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: var(--warn); background: var(--warn-bg); padding: .12rem .45rem; border-radius: 999px; }

/* qualification groups — names grouped within their qualification + slot count */
.qgroups { display: grid; gap: .5rem; margin-bottom: .55rem; }
.qgroup { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.qgroup.full { opacity: .85; }
.qgroup-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: .3rem .55rem; background: var(--accent); color: var(--navy-dark);
  font-size: .82rem; font-weight: 700;
}
.qgroup.full .qgroup-head { background: #eef1f4; color: var(--muted); }
.qgroup-head .qcount { font-variant-numeric: tabular-nums; }

/* Remove-this-level, tucked behind a × so it does not compete with the slot
   counts. Two choices open in a small menu rather than one destructive click. */
.qgroup-remove { position: relative; margin-left: .3rem; }
.qgroup-remove > summary {
  list-style: none; cursor: pointer; color: var(--muted);
  font-size: .9rem; line-height: 1; padding: 0 .2rem; border-radius: 4px;
}
.qgroup-remove > summary::-webkit-details-marker { display: none; }
.qgroup-remove > summary:hover { color: var(--danger); background: var(--danger-bg); }
.qgroup-remove-menu {
  position: absolute; right: 0; z-index: 20; min-width: 12rem;
  display: flex; flex-direction: column; gap: .25rem;
  background: #fff; border: 1px solid var(--line); border-radius: 8px;
  padding: .4rem; box-shadow: 0 8px 20px rgba(0,0,0,.12);
}
.qgroup-remove-menu .btn-cell { width: 100%; text-align: left; }
.qdot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: .4rem; vertical-align: middle; }
.qmembers { list-style: none; margin: 0; padding: .3rem .55rem; display: grid; gap: .25rem; }
.qmembers li { display: flex; align-items: center; justify-content: space-between; gap: .5rem; font-size: .85rem; }
.qmembers li.me { font-weight: 700; color: var(--navy); }
.qmembers .slot-open { color: var(--muted); font-style: italic; font-size: .78rem; }
.qmembers .tag { font-size: .66rem; text-transform: uppercase; letter-spacing: .04em; color: var(--navy-dark); background: var(--accent); border: 1px solid #b9dcee; padding: .02rem .35rem; border-radius: 999px; }
/* Every-other-week regulars: a different colour from "regular", because the
   distinction a coordinator needs at a glance is why this person is on this
   week and not next. Same shape so the two read as one family of tag. */
.qmembers .tag-alt { color: #6b4a00; background: var(--warn-bg); border-color: #e8d08a; }
/* Expected but not coming. Grey rather than a warning colour: it is a fact
   about the week, not a problem with the volunteer — the problem, if any, is
   the open slot beside it, which already reads as open. */
.qmembers .tag-out { color: var(--muted); background: transparent; border-color: var(--line); }
.qmembers .member-out { opacity: .6; }

/* The frequency radios under "add to the recurring schedule". Indented to sit
   under the checkbox they belong to.
   :not([hidden]) matters — `hidden` is only a UA-stylesheet `display: none`, so
   a bare `display: flex` here beats it and the radios show even when the script
   has hidden them. */
.recur-freq:not([hidden]) { display: flex; flex-direction: column; gap: .05rem; }
.recur-freq { margin: .1rem 0 0 1.35rem; }
.recur-freq .chk { font-size: .78rem; }
/* Touch-friendly remove: text label, comfortable tap target. */
.btn-x { border: 1px solid transparent; background: transparent; color: var(--danger); cursor: pointer; font-size: .78rem; font-weight: 600; line-height: 1; padding: .4rem .6rem; border-radius: 8px; min-height: 32px; }
.btn-x:hover { background: var(--danger-bg); border-color: #f0c5c0; }
.member-actions { display: inline-flex; align-items: center; gap: .25rem; flex: 0 0 auto; }

/* "Away this week" banner — travel blocks overlapping the viewed week,
   surfaced at the top of the coordinate page ahead of the day-by-day grid. */
.away-banner { border-color: #f0d6ad; }
.away-banner .card-body { background: var(--warn-bg); border-radius: var(--radius); }
.away-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.away-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; font-size: .88rem; }
.away-name { font-weight: 700; color: var(--navy-900); }
.away-dates { color: var(--warn); font-weight: 600; font-size: .82rem; white-space: nowrap; }
.away-note { color: var(--muted); font-size: .82rem; font-style: italic; }

/* Secondary 'end recurring' follow-up banner. */
.recur-banner { margin-bottom: 1.1rem; border-color: var(--accent-strong); }
.recur-banner .card-body { background: var(--accent); border-radius: var(--radius); }
.recur-actions { display: flex; gap: .6rem; flex-wrap: wrap; }
.recur-actions .btn { min-height: 44px; }

/* Consolidated horizontal week grid (paper-schedule style). */
/* Horizontal scrolling only. The table has a 900px min-width, so on a narrow
   window it has to scroll somewhere, and that somewhere must not be the page.

   No max-height. There used to be one (78vh) to make this a vertical scroll
   container so the sticky day header would engage. The cost was a cap: a cell
   grew by a few pixels and the whole week became a 3px-overflowing scroll
   region, which reads as a stuck page rather than as a table with more in it.
   Height now follows content, so vertical overflow cannot happen and the auto
   that overflow-x forces on the y axis never draws a bar.

   The cost is the sticky day header below, which no longer engages: sticky
   needs a scrollport that actually scrolls on that axis, and this one now only
   scrolls sideways. Handing the job to the page instead — dropping to
   `overflow: visible` above some width so the page becomes the scrollport —
   was tried and does not work. The table's real intrinsic width is not its
   declared 900px min-width but roughly 1007px (seven 130px columns plus the
   nowrap row header), it varies with how long an area's shift labels are, and
   at a 1000px window the measured result was the whole page scrolling
   sideways. No fixed breakpoint can be safe against content it cannot
   measure, and a page that scrolls sideways is worse than a header that does
   not follow. */
.week-scroll {
  overflow-x: auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); box-shadow: var(--shadow);
  overscroll-behavior: contain;
}
.week-grid { border-collapse: separate; border-spacing: 0; width: 100%; min-width: 900px; font-size: .82rem; }
.week-grid th, .week-grid td { border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); vertical-align: top; }
/* z-index must beat .rowhead (1) so the header wins where they cross. */
.week-grid thead th { background: var(--navy-900); color: #fff; padding: .5rem .6rem; text-align: left; position: sticky; top: 0; z-index: 3; }
.week-grid thead th.is-today { background: var(--navy); }
.week-grid thead .dow { font-family: var(--font-head); display: block; }
.week-grid thead .date { opacity: .75; font-size: .74rem; }
/* The corner is sticky on both axes (top: 0 comes from the thead rule above),
   so it has to sit above the header row (3) and the row headers (1). */
.week-grid .corner { background: var(--navy-900); position: sticky; left: 0; z-index: 4; }
.week-grid .rowhead { background: var(--accent); color: var(--navy-900); font-weight: 700; padding: .5rem .6rem; white-space: nowrap; position: sticky; left: 0; z-index: 1; }
.week-grid .rowhead .rowtime { display: block; font-weight: 400; color: var(--navy-dark); font-size: .72rem; }
.week-grid td { padding: .45rem .55rem; min-width: 130px; }
.week-grid td.mine { background: #f0f7fb; box-shadow: inset 3px 0 0 var(--accent-strong); }
.week-grid td.cancelled { background: repeating-linear-gradient(45deg,#faf1f0,#faf1f0 8px,#fff 8px,#fff 16px); }
/* Levels are separated so a cell reads as grouped by qualification rather than
   as one run of names. On the group, not on .gname, so names within a level
   stay tight together and only the boundary between levels opens up. */
.glevel + .glevel { margin-top: .5rem; }
.gname { font-weight: 600; line-height: 1.35; }
.gname em { font-weight: 400; color: var(--muted); font-style: normal; }
/* The trainer, under their trainee. Muted and indented so it reads as a
   detail of the name above rather than as another person on the shift — they
   are already listed in their own level, struck through. */
.gtrainer {
  font-size: .74rem; color: var(--muted); line-height: 1.3;
  padding-left: .55rem; border-left: 2px solid var(--line); margin-left: .1rem;
}
.gtrainer em { font-style: normal; font-weight: 600; }
/* A recurring volunteer who is out this week: struck through and faded, but
   still their qualification's colour so the row reads as "this person, absent"
   rather than as a different kind of entry. They hold no slot — the Open badge
   beside them is what a reader acts on. */
.gname-out { text-decoration: line-through; opacity: .55; font-weight: 500; }
.gopen {
  display: inline-block; font-size: .72rem; font-weight: 600;
  border: 1px dashed currentColor; border-radius: 6px;
  padding: .12rem .4rem; margin: .12rem .12rem 0 0;
  background: rgba(255,255,255,.5);
}
.cell-empty { color: var(--line); }
.cell-actions { margin-top: .35rem; }
/* Sign up sits at the bottom of the cell, so the buttons line up across a row
   instead of stepping up and down with each shift's roster.

   Absolute rather than a flex column pushing it down with margin-top: auto.
   That needs the wrapper to fill the cell, and a percentage height inside a
   table cell does not resolve — measured in the browser, `height: 100%` on the
   wrapper gave the same content height whether the cell declared 1px, 0, or
   100%, leaving the buttons exactly where they started. The cell reserves the
   space with padding instead, which does not depend on percentage resolution.

   Grid only: the carousel shows one shift per card, with no row of neighbours
   to line up with, so there the button stays in normal flow. */
.week-grid td { position: relative; }
.week-grid .cell-body { padding-bottom: 2.1rem; }
.week-grid .cell-actions { position: absolute; left: .55rem; bottom: .5rem; margin-top: 0; }
.btn-cell { font: inherit; font-size: .74rem; font-weight: 600; cursor: pointer; border-radius: 999px; padding: .25rem .6rem; border: 1px solid transparent; min-height: 30px; }
.btn-cell.join { background: var(--navy); color: #fff; }
.btn-cell.leave { background: var(--danger-bg); color: var(--danger); border-color: #f0c5c0; }

@media (max-width: 640px) {
  .week-grid td { min-width: 120px; }
}

/* Co-workers shown on upcoming shifts. */
.coworkers { margin-top: .5rem; display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; font-size: .8rem; }
.cw-label { color: var(--muted); }
.cw-name { background: var(--accent); color: var(--navy-dark); border: 1px solid #b9dcee; border-radius: 999px; padding: .05rem .5rem; }
/* Sized here rather than inherited: it used to sit inside .coworkers, which
   sets .8rem, and moving it to its own row left it rendering at body size. */
.cw-open { font-size: .8rem; font-weight: 600; color: var(--ok);
           background: var(--ok-bg); border-radius: 999px; padding: .05rem .5rem; }

.assign-block { padding: 0 .55rem .5rem; }
.assign-block .assign-row { padding: 0; margin: 0 0 .3rem; }
.chk { display: flex; align-items: center; gap: .35rem; font-size: .74rem; color: var(--muted); font-weight: 400; }
.chk input { width: auto; }

.pill { font-size: .72rem; padding: .12rem .5rem; border-radius: 999px; }
.pill-ok { background: var(--ok-bg); color: var(--ok); }
.pill-full { background: #eef1f4; color: var(--muted); }
.pill-cancel { background: var(--danger-bg); color: var(--danger); }

/* ---------- Messages ---------- */
.messages { max-width: 1180px; margin: 1rem auto 0; padding: 0 1.25rem; display: grid; gap: .5rem; }
.alert { padding: .7rem 1rem; border-radius: 10px; border: 1px solid; font-size: .9rem; }
.alert-success { background: var(--ok-bg); border-color: #bfe3cd; color: var(--ok); }
.alert-error, .alert-danger { background: var(--danger-bg); border-color: #f0c5c0; color: var(--danger); }
.alert-info { background: var(--accent); border-color: #b9dcee; color: var(--navy-dark); }
.alert-warning { background: var(--warn-bg); border-color: #f0d6ad; color: var(--warn); }

/* ---------- Forms ---------- */
.form-row { margin-bottom: 1rem; }
.form-row label { display: block; font-weight: 600; margin-bottom: .3rem; font-size: .92rem; }
.form-row .help { color: var(--muted); font-size: .82rem; margin-top: .2rem; }
input[type=text], input[type=email], input[type=password], input[type=date], input[type=time],
input[type=number], input[type=url], input[type=search], select, textarea {
  width: 100%; padding: .55rem .7rem; border: 1px solid var(--line); border-radius: 10px;
  font: inherit; background: #fff; color: var(--ink);
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent-strong); border-color: var(--accent-strong); }
.errorlist { color: var(--danger); font-size: .82rem; list-style: none; padding: 0; margin: .3rem 0 0; }

.auth-wrap { max-width: 420px; margin: 3rem auto; }
.auth-wrap .card-body { padding: 1.6rem; }
.center-narrow { max-width: 720px; margin: 0 auto; }

.empty { text-align: center; color: var(--muted); padding: 2rem 1rem; }
.badge-count { background: var(--accent-strong); color: var(--navy-900); border-radius: 999px; padding: .05rem .5rem; font-size: .75rem; font-weight: 700; }
.section-title { display: flex; align-items: center; gap: .6rem; margin: 1.6rem 0 .8rem; }
.section-title h2 { margin: 0; }
.muted { color: var(--muted); }
.stack > * + * { margin-top: .6rem; }
.inline-form { display: inline; }
.footer { text-align: center; color: var(--muted); font-size: .82rem; padding: 2rem 1rem; }

/* ---------- Reports ---------- */
.report-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.report-table th, .report-table td { text-align: left; padding: .45rem .5rem; border-bottom: 1px solid var(--line); }
.report-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.report-table tfoot th { border-top: 2px solid var(--line); border-bottom: none; }
.report-table .dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: .35rem; }
.month-bars { display: grid; gap: .3rem; }
.mb-row { display: grid; grid-template-columns: 2.5rem 1fr 2.8rem; align-items: center; gap: .5rem; font-size: .82rem; text-decoration: none; color: inherit; padding: .15rem .3rem; border-radius: 8px; }
a.mb-row:hover { background: var(--accent); }
a.mb-row.active { background: var(--accent); outline: 1px solid var(--accent-strong); }
.mb-label { color: var(--muted); }
.mb-track { background: #eef2f6; border-radius: 999px; height: 12px; overflow: hidden; }
.mb-fill { display: block; height: 100%; background: linear-gradient(90deg, var(--accent-strong), var(--navy)); border-radius: 999px; min-width: 2px; }
.mb-value { text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); }

.assign-row { display: flex; gap: .4rem; margin: 0; padding: 0 .55rem .5rem; }
.assign-row select { flex: 1; min-width: 0; padding: .35rem .5rem; font-size: .82rem; }
details > summary::-webkit-details-marker { display: none; }
details > summary { display: inline-flex; }

/* ---------- Mobile ---------- */
@media (max-width: 640px) {
  .site-header .bar { gap: .5rem .9rem; padding: .6rem .9rem; }
  .brand img { height: 38px; }
  .brand .title { font-size: .95rem; }
  .brand .title small { display: none; }

  /* Hamburger menu: the toggle sits inline next to the brand; the actual
     nav content drops down as a full-width panel below the header instead
     of competing for space in the header row. */
  .nav-toggle { display: inline-flex; }
  .nav-panel {
    display: none;
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch;
    background: var(--navy-dark); padding: .75rem .9rem 1rem;
    box-shadow: 0 12px 28px rgba(0,0,0,.35);
    z-index: 150; max-height: calc(100vh - 60px); overflow-y: auto;
  }
  .nav-panel.open { display: flex; }
  .nav-main { width: 100%; flex-direction: column; align-items: stretch; row-gap: .15rem; }
  .nav-links {
    flex-direction: column; align-items: stretch;
    justify-content: flex-start; row-gap: .1rem;
  }
  .nav-static {
    flex-direction: column; align-items: stretch; row-gap: .1rem;
    margin-top: .3rem; padding-top: .4rem;
    border-top: 1px solid rgba(255,255,255,.14);
  }
  .nav a { padding: .6rem .65rem; font-size: .92rem; border-radius: 8px; }
  .nav-drop-btn { width: 100%; text-align: left; padding: .6rem .65rem; font-size: .92rem; border-radius: 8px; }
  /* The submenu expands inline within the panel rather than floating —
     floating a second absolutely-positioned box inside one that's already
     absolute/full-width invites overlap and z-index fights. */
  .nav-drop-menu {
    position: static; box-shadow: none; min-width: 0;
    margin: .15rem 0 .2rem .5rem; background: rgba(0,0,0,.18);
  }
  .nav-user {
    width: 100%; justify-content: space-between;
    margin-top: .5rem; padding-top: .5rem;
    border-top: 1px solid rgba(255,255,255,.14);
  }

  .main { margin: 1rem auto; padding: 0 .9rem; }
  .page-head { flex-direction: column; align-items: stretch; gap: .6rem; }
  .page-head h1 { font-size: 1.5rem; }
  .page-head > div:last-child { display: flex; flex-wrap: wrap; }

  .grid.cols-2 { grid-template-columns: 1fr; }
  .week { grid-template-columns: 1fr; }
  .messages { padding: 0 .9rem; }

  /* Larger touch targets — WCAG 2.5.8 / Apple HIG want ~44px. .btn-x and
     .btn-cell are the primary actions on the coordinate and schedule pages
     and were measuring 32px and 30px tall. */
  .btn { padding: .6rem 1rem; min-height: 44px; }
  .btn-sm { padding: .45rem .8rem; min-height: 40px; }
  .btn-x { min-height: 44px; padding: .55rem .7rem; }
  .btn-cell { min-height: 44px; padding: .5rem .8rem; }
  .roster li { flex-wrap: wrap; }
  /* Long single-word names shouldn't spill out of the 2-column roster. */
  .roster-members li { overflow-wrap: anywhere; }
}

@media (max-width: 380px) {
  .buckets { gap: .25rem; }
  .bucket { font-size: .72rem; padding: .18rem .4rem; }
}

/* Coordinator page: roster + message history sections */
.coord-section {
  margin-top: 2rem;
}
.section-head {
  font-size: 1rem;
  font-weight: 700;
  margin: 0 0 .8rem;
  display: flex;
  align-items: center;
  gap: .6rem;
}
.roster-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: .8rem;
}
.roster-group {
  background: var(--card-bg, #fff);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: .6rem .75rem;
}
.roster-qhead {
  font-size: .82rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: .3rem;
  margin-bottom: .35rem;
}
.roster-members {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: .82rem;
  line-height: 1.65;
}
/* Wrapper scrolls the table instead of letting it widen the page — the
   column-hiding query below only fires at ≤600px, so 601–760px could push
   the whole document into horizontal scroll. */
.msg-log-scroll { overflow-x: auto; }
.msg-log {
  width: 100%;
  border-collapse: collapse;
  font-size: .85rem;
}
.msg-log th, .msg-log td {
  padding: .45rem .6rem;
  text-align: left;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.msg-log th {
  font-weight: 600;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #666;
}
@media (max-width: 600px) {
  .roster-grid { grid-template-columns: 1fr 1fr; }
  /* Drop the later columns on a phone — for the MESSAGE LOG, where columns
     4+ are secondary detail. Explicitly not the volunteer directory, which
     borrows .msg-log for its cell styling but whose columns 4+ include
     status, areas and the Edit link: hiding those left a coordinator on a
     phone with no way to open anyone's record at all. The directory stacks
     into cards instead — see .vc-table below. */
  .msg-log:not(.vc-table) th:nth-child(n+4),
  .msg-log:not(.vc-table) td:nth-child(n+4) { display: none; }
}

/* Days past the generated horizon: shown as the recurring pattern so the week
   isn't blank, but visibly not bookable. */
.week-grid td.not-published { background: repeating-linear-gradient(
    45deg, transparent, transparent 6px, rgba(0,0,0,.025) 6px, rgba(0,0,0,.025) 12px); }
.week-grid td.not-published .gopen { opacity: .55; }

/* Vacation status strip on My Shifts: full width, one line tall. It is usually
   empty, so it must cost almost no vertical space; the chips wrap only when
   someone has several trips booked. */
.vacation-strip { margin-bottom: 1.2rem; }
.vacation-strip .card-body {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  padding: .5rem .8rem;
}
.vacation-label { font-weight: 700; font-size: .85rem; }
.vacation-none { font-size: .85rem; }
.vacation-manage { margin-left: auto; font-size: .78rem; }
@media (max-width: 640px) {
  /* Keep Manage on the same line rather than letting it drop below. */
  .vacation-strip .card-body { gap: .4rem; }
}

/* Roster rows carry a level control, so they need to lay out as a row rather
   than a bare list item. */
.roster-member { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.roster-member .rm-name { flex: 1 1 auto; min-width: 0; }
.roster-member .rm-level { display: flex; align-items: center; gap: .35rem; margin: 0; }
.roster-member select { font-size: .78rem; padding: .15rem .35rem; max-width: 12rem; }

/* Level selects are hidden until a coordinator clicks "Change levels". The
   class is added by script, so with JS off they stay visible rather than
   leaving the control unreachable. */
.roster-grid.levels-hidden .rm-level { display: none; }

/* Application availability grid: a checkbox pair per day/shift. Scrolls
   sideways on a phone rather than squashing the labels. */
.avail-scroll { overflow-x: auto; margin-bottom: 1rem; }
.avail-grid { border-collapse: collapse; min-width: 26rem; }
.avail-grid th, .avail-grid td { border: 1px solid var(--line, #dde3ea); padding: .4rem .6rem; text-align: left; }
.avail-grid .rowhead { font-weight: 600; white-space: nowrap; }
.avail-cell { display: flex; align-items: center; gap: .3rem; font-size: .8rem; font-weight: 400; }
.avail-cell.avail-pref { color: var(--muted, #6B7280); }

/* Shift cards on My Shifts, both upcoming and open: what the shift is on the
   left, when it is and the action on the right, so the date and its button read
   as one thing rather than the eye tracking back to the left margin. */
.shift-split { display: flex; flex-wrap: wrap; align-items: flex-start;
               justify-content: space-between; gap: .75rem; }
/* Full-width row under both columns, so it lines up with the button's
   right edge rather than the left column's. */
.shift-split .slot-foot { flex: 1 0 100%; display: flex; justify-content: flex-end; }
/* flex-basis 0, not auto: with wrapping enabled a wide left column would
   otherwise push the date and button onto their own line instead of shrinking
   to share one. */
.shift-split .slot-main { flex: 1 1 0; min-width: 0; }
.shift-split .slot-side { flex: 0 0 auto; display: flex; flex-direction: column;
                         align-items: flex-end; gap: .45rem; text-align: right; }
.shift-split .slot-side form { margin: 0; }

/* "Waiting to be placed": one row per applicant, each with an Add button.
   Without padding the buttons sat directly on top of each other, and with a
   dozen applicants it was hard to be sure which row a click belonged to. */
.waiting-list .roster-member { padding: .45rem .55rem; border-radius: 8px; }
.waiting-list .roster-member + .roster-member { margin-top: .15rem; }
.waiting-list .roster-member:nth-child(odd) { background: rgba(20, 68, 108, .045); }
.waiting-list .roster-member:hover { background: rgba(20, 68, 108, .09); }

/* ---------- Training ---------- */
/* Same two-column shape as the shift cards: what the training is on the left,
   the action on the right. It sits at the top of My Shifts and again on the
   coordinator's list, so one rule serves both. */
.training-row { display: flex; flex-wrap: wrap; align-items: flex-start;
                justify-content: space-between; gap: .75rem; }
.training-row + .training-row { border-top: 1px solid var(--line); padding-top: .7rem; }
.training-main { flex: 1 1 0; min-width: 0; }
.training-side { flex: 0 0 auto; display: flex; flex-direction: column;
                 align-items: flex-end; gap: .35rem; text-align: right; }
.training-side form { margin: 0; }
/* Report and Archive read as one pair of choices; stacked they looked like two
   unrelated buttons and doubled the row's height. */
.training-actions { display: flex; align-items: center; gap: .35rem; }
.training-body { margin: .4rem 0 0; font-size: .9rem; white-space: normal;
                 overflow-wrap: anywhere; }
.training-ack-note { font-size: .75rem; max-width: 12rem; }
.training-count { font-size: .8rem; font-weight: 600; white-space: nowrap; }

/* Completion progress. Purely decorative — the "12 of 30" text beside it is
   what a screen reader gets, via aria-label on the track. */
.training-bar { margin-top: .45rem; height: 6px; border-radius: 999px;
                background: var(--line); overflow: hidden; max-width: 22rem; }
.training-bar span { display: block; height: 100%; background: var(--ok); }
.training-bar-lg { height: 10px; max-width: none; margin: 0 0 .8rem; }

/* Training hangs off the bottom of the Coordinate dropdown but is not an area,
   so it gets a heavier rule above it than the per-area separators. */
.nav-drop-menu a.nav-drop-sep { border-top: 1px solid rgba(255,255,255,.25); }

.training-todo { margin-bottom: 1.2rem; }
.training-todo .section-title { margin-top: 0; }

/* On a phone the two columns leave the title a word wide while the button keeps
   half the row. Titles here are sentences, not the two-word area names the
   shift cards carry, so this stacks instead of squeezing. */
@media (max-width: 560px) {
  .training-row { flex-direction: column; }
  .training-side { align-items: flex-start; text-align: left; width: 100%; }
  .training-ack-note { max-width: none; }
}

/* ---------- Day carousel (phone view of the week schedule) ---------- */
/* Eight columns cannot be read on a phone. Below this width the week grid is
   replaced by one day at a time, swiped horizontally; above it the grid is
   still the better tool, because seeing the whole week at once is the point. */
.day-carousel { display: none; }

@media (max-width: 780px) {
  .week-scroll { display: none; }
  .day-carousel { display: block; }

  /* Coordinator page: the .day cards it already renders become the panels, so
     the phone swipes through exactly what a laptop shows in three columns. */
  .week {
    display: flex; overflow-x: auto; overflow-y: hidden; gap: 0;
    scroll-snap-type: x mandatory; scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    transition: height .18s ease;
  }
  .week::-webkit-scrollbar { display: none; }
  .week > .day {
    flex: 0 0 100%; min-width: 0; scroll-snap-align: start;
    align-self: flex-start;
  }
}

/* The strip belongs to the phone view only; above the breakpoint the week is a
   grid with every day already on screen and a day picker would be noise. */
.day-carousel-inline > .dc-bar { display: none; }
@media (max-width: 780px) {
  .day-carousel-inline > .dc-bar { display: flex; }
}

/* Day strip. Sticky so the day you are on, and the way to the next one, stay
   reachable however far down a busy Saturday you have scrolled. */
.dc-bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: .25rem;
  background: var(--bg); padding: .4rem 0 .5rem;
  border-bottom: 1px solid var(--line);
}
.dc-days { display: flex; flex: 1 1 auto; gap: .15rem; justify-content: space-between; }
.dc-day {
  flex: 1 1 0; min-width: 0; padding: .3rem .1rem;
  display: flex; flex-direction: column; align-items: center; gap: .05rem;
  background: none; border: 1px solid transparent; border-radius: 10px;
  font: inherit; color: var(--ink); cursor: pointer; line-height: 1.15;
}
.dc-dow { font-size: .66rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.dc-date { font-size: .95rem; font-weight: 600; }
/* A day the area is closed still gets a tab — its absence is information, and
   a gap in the strip would misalign the week. It is just muted. */
.dc-day.is-empty .dc-date, .dc-day.is-empty .dc-dow { opacity: .38; }
.dc-day.is-today .dc-date { color: var(--navy); text-decoration: underline; text-underline-offset: 3px; }
.dc-day.is-active { background: var(--navy); border-color: var(--navy); }
.dc-day.is-active .dc-date, .dc-day.is-active .dc-dow { color: #fff; opacity: 1; }
.dc-day:focus-visible { outline: 2px solid var(--accent-strong); }

.dc-arrow {
  flex: 0 0 auto; width: 34px; height: 34px;
  background: none; border: 1px solid var(--line); border-radius: 999px;
  font-size: 1.25rem; line-height: 1; color: var(--navy); cursor: pointer;
}
.dc-arrow:active { background: var(--accent); }

/* The track. overflow-y is hidden and the height is pinned to the active panel
   by JS, so vertical scrolling belongs to the page rather than to a nested
   scroller — a thumb dragging up expects the header to move away. */
.dc-track {
  display: flex; overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch; scrollbar-width: none;
  transition: height .18s ease;
}
.dc-track::-webkit-scrollbar { display: none; }
.dc-panel {
  flex: 0 0 100%; min-width: 0; scroll-snap-align: start;
  padding: .2rem .1rem 1rem;
}

.dc-heading {
  font-size: 1rem; margin: .5rem 0 .6rem;
  display: flex; align-items: center; gap: .5rem;
}
.dc-today {
  font-family: var(--font-body); font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  background: var(--accent); color: var(--navy-dark);
  padding: .1rem .45rem; border-radius: 999px;
}

.dc-shift {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .8rem .9rem; margin-bottom: .6rem;
}
.dc-shift + .dc-shift { margin-top: 0; }
.dc-shift-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .5rem; flex-wrap: wrap; margin-bottom: .5rem;
}
/* Same accents the grid uses, so a shift reads the same on either screen. */
.dc-shift.mine { border-color: var(--accent-strong); background: #f7fcff; }
.dc-shift.cancelled { opacity: .6; }
.dc-shift.not-published {
  background: repeating-linear-gradient(
    45deg, transparent, transparent 6px, rgba(0,0,0,.025) 6px, rgba(0,0,0,.025) 12px);
}
.dc-shift.not-published .gopen { opacity: .55; }
/* In the grid these sit in a tight cell; here there is room to breathe. */
.dc-shift .gname, .dc-shift .gopen { font-size: .88rem; }
.dc-shift .gtrainer { font-size: .8rem; }
/* One shift per card here, so there is no row of cells to line the button up
   with — a plain gap after the last name is what reads correctly. padding-top
   is zeroed so this is the whole spacing, not .5rem on top of the grid's. */
.dc-shift .cell-actions { margin-top: .5rem; padding-top: 0; }
.dc-shift .cell-actions .btn-cell { padding: .4rem .9rem; font-size: .85rem; }

.schedule-note { font-size: .8rem; margin-top: .6rem; }

/* ---------- Applicant detail + add volunteer ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Definition lists carry the application: label above value, so a long answer
   is not squeezed into a narrow second column on a phone. */
.kv { margin: 0; }
.kv dt {
  font-size: .74rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); font-weight: 600;
}
.kv dd { margin: .1rem 0 .8rem; overflow-wrap: anywhere; }
.kv dd:last-child { margin-bottom: 0; }

/* Stated availability. A grid because "who is free Tuesday morning" is read by
   scanning a column, which prose cannot support. */
.avail-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
.avail-table th { text-align: left; font-weight: 600; padding: .25rem .4rem; }
.avail-table thead th { color: var(--muted); font-size: .74rem; text-transform: uppercase; }
.avail-table td { text-align: center; padding: .25rem .4rem; color: var(--line); }
.avail-table td.yes { color: var(--ok); font-weight: 700; }
.avail-table tbody tr:nth-child(odd) { background: rgba(20, 68, 108, .04); }

/* ---------- Volunteer directory ---------- */
.vc-schedule-links { display: flex; gap: .5rem; flex-wrap: wrap; }

/* Search form: label-above-input fields that wrap and share a row on wide
   screens, one column on a phone — same shape as .form-row already uses
   elsewhere, just laid out as a row here instead of stacked. */
.vc-filters { display: flex; flex-wrap: wrap; gap: .9rem 1rem; align-items: flex-end; }
.vc-filters .form-row { margin-bottom: 0; flex: 1 1 11rem; min-width: 9rem; }
/* Wider than the filter dropdowns: a search value is a name or a full email
   address, both of which are longer than "Approved volunteer". */
.vc-filters .vc-search-row { flex: 2 1 22rem; }
.vc-placeholder-chk { flex: 1 1 100%; order: 5; }
.vc-filter-actions { display: flex; gap: .5rem; flex: 1 1 100%; order: 6; align-items: center; }
.vc-searching { color: var(--muted); font-size: .85rem; }

.vc-exports { display: flex; gap: .4rem; margin-left: auto; }

@media (max-width: 600px) {
  /* "Results (134)" and the two export buttons do not fit on one 375px line;
     let the buttons drop to their own row instead of squeezing the count. */
  .section-head { flex-wrap: wrap; }
  .vc-exports { margin-left: 0; width: 100%; }
  .vc-exports .btn { flex: 1 1 auto; justify-content: center; }
  /* Search and Clear side by side, each sharing the width — comfortable taps
     without either running the full width of the screen. */
  .vc-filter-actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* Collapsible section. <details>/<summary> rather than a JS toggle: it opens
   without script, Ctrl-F reaches the closed content in some browsers, and the
   open/closed state is exposed to assistive tech for free. */
.vc-collapse > summary {
  cursor: pointer;
  list-style: none;          /* the default marker sits badly beside a flex heading */
  user-select: none;
}
.vc-collapse > summary::-webkit-details-marker { display: none; }
.vc-collapse > summary::before {
  content: "▸";
  color: var(--muted);
  font-size: .8em;
  transition: transform .12s ease;
  display: inline-block;
}
.vc-collapse[open] > summary::before { transform: rotate(90deg); }
.vc-collapse > summary:hover { color: var(--navy); }

.vc-table th:nth-child(3), .vc-table td:nth-child(3),
.vc-table th:nth-child(4), .vc-table td:nth-child(4) {
  white-space: nowrap;
}
.vc-pager {
  display: flex; align-items: center; justify-content: center; gap: .8rem;
  margin-top: .9rem;
}

/* Directory on a phone or tablet: each volunteer becomes a card rather than a
   row in a table scrolled sideways. Eight columns cannot be read at 375px, and
   the alternative already in the stylesheet — hiding columns 4+ — took the Edit
   link with it, which is the one control this page exists to offer.
   780px, not 600: the table's own content needs ~713px, so everything below
   roughly 785px scrolled sideways — including iPad portrait at 768, where
   reaching Edit meant a horizontal swipe. */
@media (max-width: 780px) {
  .vc-table thead { display: none; }
  .vc-table, .vc-table tbody, .vc-table tr, .vc-table td { display: block; }
  .vc-table tr {
    border: 1px solid var(--line); border-radius: 12px;
    padding: .7rem .8rem; margin-bottom: .7rem; background: #fff;
  }
  .vc-table tr:last-child { margin-bottom: 0; }
  .vc-table td {
    border-bottom: none; padding: .15rem 0;
    /* Undo the desktop nowrap on phone/city: here there is no sideways
       scroll to escape into, so a long value must wrap. */
    white-space: normal;
  }
  /* Label/value pairs for the ordinary fields, caption from data-label. */
  .vc-table td[data-label] {
    display: flex; gap: .8rem; justify-content: space-between;
    align-items: baseline;
  }
  .vc-table td[data-label]::before {
    content: attr(data-label);
    flex: none; font-size: .78rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: .04em; color: #666;
  }
  /* The name is the card's heading, so it gets no caption. */
  .vc-cell-name {
    font-weight: 700; font-size: 1rem;
    padding-bottom: .4rem !important; margin-bottom: .3rem;
    border-bottom: 1px solid var(--line) !important;
  }
  /* Long addresses must break rather than force the card wider. */
  .vc-cell-email { text-align: right; overflow-wrap: anywhere; }
  /* Nothing to say, so no row — see vc-empty in the template. */
  .vc-table td.vc-empty { display: none; }
  /* Full-width tap target. The margin lives on the button, not the cell, so
     a staff row — where the link is deliberately absent — leaves no gap
     behind. (:empty would not help: template whitespace fills the cell.) */
  .vc-cell-actions .btn {
    width: 100%; justify-content: center; margin-top: .6rem;
  }
}

/* ---------- Volunteer detail (personal file) ---------- */
.vd-status-form, .vd-email-form {
  display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin: 0;
}
.vd-status-form select { width: auto; min-width: 10rem; }
.vd-email-form input { flex: 1 1 14rem; width: auto; }

.vd-change-log { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.vd-change-log li { display: flex; flex-direction: column; gap: .1rem; border-bottom: 1px solid var(--line); padding-bottom: .5rem; }
.vd-change-log li:last-child { border-bottom: none; padding-bottom: 0; }
.vd-change-field { font-weight: 600; font-size: .85rem; text-transform: capitalize; }

.vd-membership-table { width: 100%; border-collapse: collapse; }
.vd-membership-table th { text-align: left; font-weight: 600; padding: .5rem .3rem; font-size: .9rem; }
.vd-membership-table td { padding: .4rem .3rem; }
.vd-membership-table tr + tr th, .vd-membership-table tr + tr td { border-top: 1px solid var(--line); }
.vd-membership-form { display: flex; gap: .4rem; align-items: center; margin: 0; }
.vd-membership-form select { width: auto; min-width: 9rem; }

/* ---------- Recurring events ---------- */
/* Weekly things with no slots. Styled as a note pinned to the day rather than
   as a shift, because nothing here is bookable and it must not read as one. */
.event {
  display: flex; align-items: baseline; gap: .4rem; flex-wrap: wrap;
  padding: .3rem .55rem; margin-bottom: .4rem;
  background: var(--accent); border-left: 3px solid var(--navy);
  border-radius: 6px; font-size: .8rem;
}
.event-title { font-weight: 600; }
.event-time { color: var(--muted); font-size: .74rem; }
.event .btn-x { margin-left: auto; }
/* Volunteer grid: a chip under the day heading, read-only. */
.event-chip {
  display: block; margin-top: .25rem;
  font-size: .68rem; font-weight: 600; line-height: 1.3;
  color: var(--navy-dark); background: var(--accent);
  border-radius: 4px; padding: .1rem .3rem;
}
.add-event { position: relative; }
.add-event > summary { list-style: none; cursor: pointer; }
.add-event > summary::-webkit-details-marker { display: none; }
.add-event-form {
  position: absolute; right: 0; z-index: 30; margin-top: .35rem;
  display: flex; flex-direction: column; gap: .35rem; width: 15rem;
  background: #fff; border: 1px solid var(--line); border-radius: 10px;
  padding: .6rem; box-shadow: 0 10px 24px rgba(0,0,0,.14);
}

/* Trainer picker, shown only on coordinator-assigned levels. */
.trainer-form { flex-basis: 100%; margin: .15rem 0 0; }
.trainer-form select { font-size: .74rem; padding: .1rem .3rem; max-width: 12rem; }
/* The time on a grid chip: its own line so a narrow column stays readable. */
.event-chip-time { display: block; font-weight: 400; color: var(--navy); opacity: .8; }
