:root, html[data-theme="dark"] {
  --bg: #05050f;
  --bg-rgb: 5, 5, 15;
  --bg-glow: #171732;
  --bg-alt: rgba(13, 13, 28, 0.75);
  --card: rgba(17, 17, 31, 0.72);
  --card-border: rgba(192, 240, 255, 0.3);
  --text: #eef8ff;
  --text-dim: #99aabb;
  --accent: #aaffee;
  --accent-dim: #6fe6c9;
  --accent-rgb: 170, 255, 238;
  --accent-text: #d7fff3;
  --blue: #c0f0ff;
  --blue-rgb: 192, 240, 255;
  --blue-text: #d6f4ff;
  --lavender: #d0aaff;
  --lavender-rgb: 208, 170, 255;
  --lavender-text: #ecdcff;
  --warn: #f59e0b;
  --warn-rgb: 245, 158, 11;
  --warn-text: #fde68a;
  --danger: #f87171;
  --danger-rgb: 248, 113, 113;
  --danger-text: #fecaca;
  --on-accent: #05050f;
  --radius: 16px;
  --shadow: 0 10px 30px rgba(0,0,0,0.5), 0 0 22px rgba(192,240,255,0.06);
  --ambient:
    radial-gradient(ellipse 620px 380px at 18% 21%, rgba(192, 240, 255, 0.22), transparent 60%),
    radial-gradient(ellipse 620px 380px at 84% 40%, rgba(208, 170, 255, 0.2), transparent 60%),
    radial-gradient(ellipse 640px 380px at 30% 59%, rgba(255, 208, 240, 0.18), transparent 60%),
    radial-gradient(ellipse 620px 380px at 80% 79%, rgba(170, 255, 238, 0.18), transparent 60%);
  --particle-colors: #c0f0ff, #d0aaff, #aaffee, #ffe8ff, #ffd0f0, #c8ffcc;
}

html[data-theme="light"] {
  --bg: #f3f6fb;
  --bg-rgb: 243, 246, 251;
  --bg-glow: #e2ecfa;
  --bg-alt: #e8eef6;
  --card: #ffffff;
  --card-border: #d7e1ee;
  --text: #16202e;
  --text-dim: #5b6b80;
  --accent: #16a34a;
  --accent-dim: #15803d;
  --accent-rgb: 22, 163, 74;
  --accent-text: #15803d;
  --blue: #0284c7;
  --blue-rgb: 2, 132, 199;
  --blue-text: #075985;
  --lavender: #7c3aed;
  --lavender-rgb: 124, 58, 237;
  --lavender-text: #5b21b6;
  --warn: #d97706;
  --warn-rgb: 217, 119, 6;
  --warn-text: #92400e;
  --danger: #dc2626;
  --danger-rgb: 220, 38, 38;
  --danger-text: #b91c1c;
  --on-accent: #06202f;
  --radius: 16px;
  --shadow: 0 10px 24px rgba(22,32,46,0.1);
}

* { box-sizing: border-box; }

html {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

body {
  margin: 0;
  min-height: 100vh;
  position: relative;
  overflow-x: hidden;
  background: var(--bg);
  color: var(--text);
  /* Reserves enough room at the end of the list to fully clear BOTH
     floating elements stacked at the bottom (the day-tabs dock, plus the
     scroll-top button sitting above it) — not just the dock alone, which
     is what left the last row or two peeking out from under the button
     with no room left to scroll past it. --daytabs-h is the same live
     measurement the button's own position is built from (see
     .scroll-top-btn), so this stays in sync if that ever changes; +76px
     covers the button's own 12px gap + 44px height + a little breathing
     room beyond just barely clearing it. */
  padding-bottom: calc(var(--daytabs-h, 68px) + 76px + env(safe-area-inset-bottom, 0px));
  transition: background-color 0.25s ease, color 0.25s ease;
}

/* Ambient glow layer behind the whole page — same technique as
   RoyinWebPortfolio's Holographic theme. Positioned absolute (not fixed) so
   it spans the full scrollable page rather than just the first viewport,
   and tiles vertically so the misty look stays consistent no matter how
   long the roster gets. Only lit up in dark mode; light mode's .bg-ambient
   stays a plain empty layer. */
.bg-ambient {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
html[data-theme="dark"] .bg-ambient {
  background-image: var(--ambient);
  background-repeat: repeat-y;
  background-size: 100% 1400px;
}

.particle {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
}
html[data-theme="dark"] .particle {
  animation: particleDrift linear infinite;
}
@keyframes particleDrift {
  0% { transform: translateY(0) translateX(0); opacity: 0.8; }
  50% { opacity: 0.4; }
  100% { transform: translateY(-90px) translateX(var(--drift)); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .particle { animation: none !important; }
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  /* On an installed iOS PWA (viewport-fit=cover) the page runs under the
     status bar / Dynamic Island — pad the bar down past it, and past the
     side insets when the phone is rotated. The background fills the inset
     too, so it reads as one solid bar. */
  padding: calc(14px + env(safe-area-inset-top, 0px)) calc(20px + env(safe-area-inset-right, 0px)) 14px calc(20px + env(safe-area-inset-left, 0px));
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgb(var(--bg-rgb));
  border-bottom: 1px solid var(--card-border);
  flex-wrap: wrap;
}

.brand { font-size: 1.2rem; font-weight: 800; letter-spacing: -0.02em; }

.sync-status {
  font-size: 0.72rem; font-weight: 700;
  padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--card-border);
  white-space: nowrap;
}
.sync-status.is-syncing { color: var(--text-dim); }
.sync-status.is-pending { color: var(--warn-text); border-color: var(--warn); background: rgba(var(--warn-rgb), 0.12); }
.sync-status.is-offline { color: var(--danger-text); border-color: var(--danger); background: rgba(var(--danger-rgb), 0.12); }
/* margin-left:auto (on top of .topbar's own justify-content:space-between)
   is what keeps this pinned to the right even when the topbar is narrow
   enough to wrap it onto its own line below the brand — without it,
   a wrapped line with only one flex item just sits at that line's start
   (the left) instead of pushing right. */
.topbar-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }

#access-gate {
  background: var(--bg);
  z-index: 100;
}
#access-gate.hidden { display: none; }

.theme-toggle-btn {
  border: 1px solid var(--card-border);
  background: var(--card);
  color: var(--text);
  border-radius: 999px;
  padding: 7px 12px;
  font-weight: 600;
  font-size: 0.78rem;
  cursor: pointer;
}
.theme-toggle-btn:active { transform: scale(0.95); }

.app {
  max-width: 1000px;
  margin: 0 auto;
  padding: 16px 16px 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.view-disclaimer {
  margin: 0;
  font-size: 0.78rem;
  color: var(--text-dim);
  background: var(--bg-alt);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 8px 12px;
}

/* Soft blurred scrim behind the floating day-tabs dock, so roster rows
   fade/blur as they scroll underneath instead of scrolling up sharply
   against the bar's edge. Sits just behind .day-tabs, ignores clicks. */
.day-tabs-scrim {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: 100px;
  z-index: 29;
  pointer-events: none;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  -webkit-mask-image: linear-gradient(to top, black 45%, transparent 100%);
  mask-image: linear-gradient(to top, black 45%, transparent 100%);
}

/* Day-of-week tabs — filter the roster to kids scheduled that day.
   Fixed to the bottom of the viewport as a floating dock, matching the
   topbar's sticky glass treatment. */
.day-tabs {
  display: flex;
  gap: 4px;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 4px;
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  max-width: 968px;
  margin: 0 auto;
  z-index: 30;
  box-shadow: var(--shadow);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.day-tab {
  flex: 1;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-weight: 700;
  font-size: 0.82rem;
  padding: 9px 4px;
  border-radius: 9px;
  cursor: pointer;
}
.day-tab.active { background: var(--blue); color: var(--on-accent); }

/* Camps' equivalent of the Day-tabs dock — filters by Program/Location
   instead of weekday. Tab count varies (however many programs are actually
   in use today), so unlike .day-tab this isn't flex:1 equal-width
   — buttons size to their own label and the row scrolls horizontally
   instead of squeezing arbitrarily many tabs into a fixed width. */
.camp-location-tabs {
  display: flex;
  gap: 4px;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 4px;
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  max-width: 968px;
  margin: 0 auto;
  z-index: 30;
  box-shadow: var(--shadow);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.camp-location-tab {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-weight: 700;
  font-size: 0.82rem;
  padding: 9px 14px;
  border-radius: 9px;
  cursor: pointer;
  white-space: nowrap;
}
.camp-location-tab.active { background: var(--blue); color: var(--on-accent); }

/* Scroll-to-top — a small glass circle matching the 44px stage buttons
   used everywhere else, not a bold primary-styled button, since this is a
   convenience action rather than a main one. --daytabs-h (measured in JS,
   same technique as --topbar-h/--gridhead-h) keeps it clear of the
   floating day-tabs dock in Check-In view; it keeps that same offset in
   Profiles view too (where the dock is hidden) so it doesn't jump position
   when switching views. Shown/hidden by toggling .visible — tied to the
   same "has the grid header actually stuck" signal already computed for
   the sticky header, not a separate scroll-position listener. */
.scroll-top-btn {
  position: fixed;
  right: 16px;
  bottom: calc(var(--daytabs-h, 68px) + 12px);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--card-border);
  background: rgba(var(--bg-rgb), 0.75);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  font-size: 1.1rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--shadow);
  z-index: 28;
  opacity: 0;
  transform: scale(0.85);
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.scroll-top-btn.visible { opacity: 1; transform: scale(1); pointer-events: auto; }
.scroll-top-btn:active { transform: scale(0.92); }

/* View tabs — Check-In (day-filtered, live Bus/In/Out ops) vs Profiles
   (full unfiltered roster, editing, delete, history/calendar). */
.view-tabs { display: flex; gap: 4px; background: var(--card); border: 1px solid var(--card-border); border-radius: 12px; padding: 4px; }
.view-tab {
  flex: 1;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-weight: 700;
  font-size: 0.85rem;
  padding: 9px 4px;
  border-radius: 9px;
  cursor: pointer;
}
.view-tab.active { background: var(--blue); color: var(--on-accent); }
/* 4+ tabs: don't cram — let them size to content and scroll sideways */
.view-tabs.scrollable { overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.view-tabs.scrollable::-webkit-scrollbar { display: none; }
.view-tabs.scrollable .view-tab { flex: 0 0 auto; white-space: nowrap; padding-left: 12px; padding-right: 12px; }

.cat-tab-toggle {
  background: none; border: none; cursor: pointer; padding: 0 2px;
  font-size: 0.95rem; filter: grayscale(1) opacity(0.45);
  transition: filter 0.12s ease;
}
.cat-tab-toggle:hover { filter: grayscale(0.4) opacity(0.8); }
.cat-tab-toggle.on { filter: none; }

/* Profiles: Kids | Coaches sub-toggle */
.pm-toggle {
  display: flex; gap: 4px; margin: 8px 0 0;
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: 10px; padding: 3px; max-width: 220px;
}
.pm-tab {
  flex: 1; border: none; background: transparent; color: var(--text-dim);
  font-weight: 700; font-size: 0.8rem; padding: 6px 4px; border-radius: 7px; cursor: pointer;
}
.pm-tab.active { background: var(--blue); color: var(--on-accent); }

/* coach cards / directory (rendered into #schools-container) */
.coach-card {
  border: 1px solid var(--card-border); border-radius: 12px;
  padding: 14px 16px; margin-bottom: 10px; background: var(--card);
  display: flex; flex-direction: column; gap: 8px;
}
.coach-card .cc-name { font-weight: 800; font-size: 1rem; }
.coach-card .cc-sub { font-size: 0.8rem; color: var(--text-dim); word-break: break-word; }
.coach-card .cc-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.coach-card .cc-row label { font-size: 0.76rem; color: var(--text-dim); font-weight: 700; }
.coach-card select, .coach-card input[type="text"], .coach-card input[type="tel"] {
  padding: 6px 8px; font-size: 0.82rem;
  background: var(--input-bg, rgba(255,255,255,0.05));
  color: var(--text); border: 1px solid var(--card-border); border-radius: 8px;
}
.coach-card .cc-tabs { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.coach-card .cc-tabs label { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; color: var(--text); }
.coach-card .cc-actions { display: flex; justify-content: flex-end; }
.coach-card.is-disabled { opacity: 0.55; }
.coach-card.is-pending { border-color: #d8a13a; background: rgba(216,161,58,0.08); }

.dir-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 11px 14px; border: 1px solid var(--card-border); border-radius: 10px; margin-bottom: 8px;
}
.dir-row .dir-name { font-weight: 700; }
.dir-row .dir-title { font-size: 0.78rem; color: var(--text-dim); margin-left: 6px; }
.dir-row a.dir-phone { font-weight: 700; text-decoration: none; color: var(--blue); white-space: nowrap; }
.dir-row .dir-nophone { font-size: 0.78rem; color: var(--text-dim); font-style: italic; }
.dir-row .dir-email { font-size: 0.72rem; color: var(--text-dim); word-break: break-all; margin-top: 2px; }

.bulk-add-list {
  list-style: none; margin: 8px 0 0; padding: 4px;
  max-height: 46vh; overflow-y: auto;
  border: 1px solid var(--card-border); border-radius: 10px;
}
.bulk-add-list li { display: flex; align-items: center; gap: 9px; padding: 8px 8px; border-radius: 8px; }
.bulk-add-list li + li { border-top: 1px solid var(--card-border); }
.bulk-add-list li.is-in { opacity: 0.5; }
.bulk-add-list label { display: flex; align-items: center; gap: 9px; cursor: pointer; flex: 1; }
.bulk-add-list .ba-name { font-weight: 600; }
.bulk-add-list .ba-sub { font-size: 0.76rem; color: var(--text-dim); }
.bulk-add-list .ba-in { margin-left: auto; font-size: 0.72rem; color: var(--text-dim); font-style: italic; }
.bulk-add-empty { padding: 14px 8px; font-size: 0.82rem; color: var(--text-dim); }

/* Toolbar */
.toolbar { display: flex; align-items: center; gap: 10px; }
.search-input {
  flex: 1;
  min-width: 0;
  padding: 11px 14px;
  border-radius: 12px;
  border: 1px solid var(--card-border);
  background: var(--card);
  color: var(--text);
  font-size: 0.95rem;
}
.search-input:focus { outline: 2px solid var(--blue); }
.search-input::placeholder { color: var(--text-dim); }

.btn {
  border: none;
  border-radius: 10px;
  padding: 10px 16px;
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
  transition: transform 0.15s ease, filter 0.15s ease;
}
.btn:active { transform: scale(0.96); }
.btn-primary { background: linear-gradient(135deg, var(--blue), var(--accent)); color: var(--on-accent); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-secondary { background: var(--bg-alt); color: var(--text); border: 1px solid var(--card-border); }
.btn-small { padding: 7px 12px; font-size: 0.78rem; }
.btn-danger-text { background: transparent; color: var(--danger); border: 1px solid rgba(var(--danger-rgb), 0.4); }
.btn-danger-solid { background: var(--danger); color: #2a0a0a; }
.btn-danger-solid:hover { filter: brightness(1.08); }
#demo-mode-btn.demo-active { background: rgba(var(--warn-rgb), 0.18); border-color: rgba(var(--warn-rgb), 0.5); color: var(--warn-text); }
.hidden { display: none !important; }

/* Grid header — sticky below the topbar (offset computed in JS via
   syncStickyOffsets, since the topbar's height can vary). The bar itself
   (.grid-head) is just the sticky/background shell; the actual columns
   live in .grid-head-inner so their horizontal position can be kept
   aligned with the kid rows below independently of how wide the bar
   itself is — see .is-stuck below. */
.grid-scroll { overflow-x: auto; }
.grid-head {
  padding: 8px 0;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-dim);
  position: sticky;
  top: var(--topbar-h, 60px);
  z-index: 25;
  /* Same blue/accent tint as the school pill's gradient, at half strength —
     a visual step between the flat topbar above and the fully-tinted pill
     below, instead of matching the topbar exactly. */
  background: linear-gradient(90deg, rgba(var(--blue-rgb), 0.08), rgba(var(--accent-rgb), 0.04)), rgb(var(--bg-rgb));
  border: 1px solid var(--card-border);
  border-radius: 12px;
  /* Geometry (width / margin / border-radius) SNAPS between stuck and
     unstuck — animating those runs a full layout recalc every frame while
     the user is mid-scroll, which is the source of the sticky jank. Only
     the paint-cheap properties ease. Promote to its own compositing layer
     so the .is-stuck class flip repaints just this bar, not the page. */
  transition: border-color 0.2s ease, background-color 0.2s ease;
  transform: translateZ(0);
}
.grid-head-inner {
  display: grid;
  grid-template-columns: 46px minmax(120px, 1fr) 110px 46px 46px 46px;
  gap: 6px;
  padding: 0 12px;
}
.grid-head-inner.profiles-mode { grid-template-columns: minmax(120px, 1fr) 1fr; }
.grid-head-inner.camp-location-mode { grid-template-columns: minmax(120px, 1fr) 110px 46px 46px; }
.grid-head-inner > span { text-align: center; line-height: 1.15; word-break: break-word; min-width: 0; }
.grid-head-inner .col-name { text-align: left; }

/* Once scrolled past the point where it starts sticking (see the
   IntersectionObserver on #grid-head-sentinel), the bar smoothly grows
   edge-to-edge to touch the sides of the page. Its columns need a bigger
   inset at that point, though: unstuck, the bar sits inside <main class="app">
   and inherits that column's 16px edge padding for free; stuck, it has
   broken out of that column entirely, so .grid-head-inner has to rebuild
   the same 1000px-centered column (see .app) itself, plus the bar's own
   original 12px+1px inset, to land exactly back over the kid rows below. */
#grid-head-sentinel { height: 0; }
.grid-head.is-stuck {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  border-radius: 0;
  border-left: none;
  border-right: none;
}
.grid-head.is-stuck .grid-head-inner {
  max-width: 1000px;
  margin: 0 auto;
  padding: 0 29px;
}

/* Schools accordion */
.schools-container { display: flex; flex-direction: column; gap: 12px; }
.camps-view { padding-top: 8px; }

.school-section {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

/* No overflow:hidden on .school-section — that would clip position:sticky
   on .school-header to this box's own scroll context in some browsers.
   Rounded corners are instead applied directly to the header (top) and
   body (bottom), which achieves the same visual clipping without breaking
   the sticky behavior. */
.school-header {
  cursor: pointer;
  background: linear-gradient(90deg, rgba(var(--blue-rgb), 0.16), rgba(var(--accent-rgb), 0.08)), rgb(var(--bg-rgb));
  border-bottom: 1px solid var(--card-border);
  border-radius: var(--radius) var(--radius) 0 0;
  position: sticky;
  top: calc(var(--topbar-h, 60px) + var(--gridhead-h, 40px));
  z-index: 20;
  /* Own compositing layer: keeps the stuck/unstuck repaint local and the
     native sticky slide smooth. Geometry here already snaps (no transition). */
  transform: translateZ(0);
}
.school-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  /* No transition here on purpose: the outer bar is deliberately
     transparent (see .school-header.is-stuck), so while this pill is
     mid-animation toward its final size it's briefly smaller than its
     resting size — exposing more of that transparent gutter than usual,
     which is exactly what let row content flash through during the
     grow animation. Snapping straight to the final size avoids that
     in-between state entirely. */
}
.school-section.collapsed .school-header { border-radius: var(--radius); border-bottom: none; }
.school-header-left { display: flex; align-items: center; gap: 8px; }
.school-name { margin: 0; font-size: 0.95rem; font-weight: 800; color: var(--blue); }
.school-caret { font-size: 0.75rem; color: var(--text-dim); transition: transform 0.2s ease; }
.school-section.collapsed .school-caret { transform: rotate(-90deg); }

/* Once stuck, the header becomes a solid full-width bar (same 100vw
   breakout trick as .grid-head/.is-stuck) — opaque so scrolled-past rows
   can't show through it — and .school-header-inner becomes a centered
   pill floating on top of that bar, half its width, with its own rounded
   border matching the Lock/Manage/Demo Mode buttons' border-radius. Going
   full-width first is what gives the pill an unambiguous 100vw-wide box
   to center a percentage-width child within. */
.school-header-sentinel { height: 0; }
.school-header.is-stuck {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: transparent;
  border-bottom: none;
  border-radius: 0;
}
.school-header.is-stuck .school-header-inner {
  /* The grid header's own not-stuck width (.app's content box — the same
     width the kid rows below already are) plus a fixed 40px, instead of
     scaling between the grid header's two widths. On screens under
     ~1030px that raw value would exceed the viewport itself (there's no
     .app max-width headroom left to add 40px on top of), so it's capped
     to leave a minimum 8px clear on each side — the fixed +40px growth
     only shows up once there's actually room for it. */
  width: min(calc(min(100vw, 1000px) - 32px + 40px), calc(100vw - 16px));
  margin: 6px auto;
  justify-content: flex-start;
  /* Same overall thickness as the not-stuck state: 11px padding + this
     pill's own 1px border (which the not-stuck header doesn't have, its
     border lives on the outer bar instead) adds up to the same 12px the
     not-stuck version gets from padding alone. */
  padding: 11px 16px;
  background: linear-gradient(90deg, rgba(var(--blue-rgb), 0.16), rgba(var(--accent-rgb), 0.08)), rgb(var(--bg-rgb));
  border: 1px solid var(--card-border);
  border-radius: 10px;
}

.school-body { display: flex; flex-direction: column; border-radius: 0 0 var(--radius) var(--radius); overflow: hidden; }
.school-section.collapsed .school-body { display: none; }
.school-empty { padding: 12px 14px; font-size: 0.8rem; color: var(--text-dim); }

/* Kid row — the whole row (aside from the stage buttons) is the expand
   target, so it needs its own pointer cursor. */
.kid-row {
  display: grid;
  grid-template-columns: 46px minmax(120px, 1fr) 110px 46px 46px 46px;
  gap: 6px;
  align-items: center;
  padding: 10px 12px;
  border-top: 1px solid var(--card-border);
  cursor: pointer;
}
.kid-row:hover { background: rgba(var(--blue-rgb), 0.06); }
/* Marked "not coming today" — the collapsed row greys back and Bus/In/Out
   are disabled (see buildCheckinRow), but the row still expands and the
   Away button stays live to toggle back. Only the header cells dim, never
   the expanded detail panel, so contacts stay readable for the phone call. */
.kid-row.not-coming .kid-name-cell,
.kid-row.not-coming .program-cell { opacity: 0.45; }
.kid-row.not-coming .kid-avatar { filter: grayscale(1); }
.kid-row.profile-row { grid-template-columns: minmax(96px, 0.85fr) 1.15fr; }
/* Camps, viewing one specific Location tab — Name | Program | In | Out,
   the same column shape as After School's Check-In row minus Bus. */
.kid-row.camp-location-mode { grid-template-columns: minmax(120px, 1fr) 110px 46px 46px; }
/* Stacked label-above-number, both allowed to wrap — a phone number needs
   to stay fully readable (area code included), and wrapping the label
   above it is more reliable for that than fitting one line and
   ellipsis-ing the overflow, which was cutting numbers off. */
.profile-contact-cell { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.contact-label { font-size: 0.72rem; font-weight: 500; color: var(--text-dim); overflow-wrap: break-word; }
.contact-number { font-size: 0.86rem; font-weight: 700; color: var(--text); overflow-wrap: break-word; }

/* touch-action:pan-y tells the browser to keep handling vertical page
   scrolling natively here, while leaving horizontal movement free for our
   own swipe-to-advance gesture (see onSchoolsPointerMove) instead of the
   two fighting each other. */
.kid-name-cell { display: flex; align-items: center; gap: 8px; min-width: 0; touch-action: pan-y; }
.kid-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 0.78rem; color: #06202f; flex-shrink: 0;
}
.kid-name-text { min-width: 0; display: flex; flex-direction: column; line-height: 1.15; }
.kid-name-text .kn-first, .kid-name-text .kn-last { font-weight: 400; font-size: 0.88rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kn-nickname { font-weight: 400; font-style: italic; color: var(--text-dim); }
/* "Drop-in" tag under the name on the roster — this kid is here today on an
   extra date, not their normal schedule, so pickup should be double-checked. */
.drop-in-badge {
  align-self: flex-start;
  margin-top: 2px;
  padding: 0 6px;
  border-radius: 999px;
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--accent);
  background: rgba(var(--accent-rgb), 0.15);
  border: 1px solid rgba(var(--accent-rgb), 0.4);
}

.program-cell { display: flex; flex-direction: column; gap: 4px; }
.program-pill {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--text-dim);
  background: var(--bg-alt);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 3px 6px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.program-pill-empty { opacity: 0.7; }

.stage-btn {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  color: var(--text-dim);
  font-size: 1rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.1;
  padding: 2px;
}
.stage-btn.done { background: rgba(var(--accent-rgb), 0.18); border-color: rgba(var(--accent-rgb), 0.5); color: var(--accent); }
.stage-btn.out-done { background: rgba(var(--blue-rgb), 0.18); border-color: rgba(var(--blue-rgb), 0.5); color: var(--blue); }
.stage-btn.absent { background: rgba(var(--danger-rgb), 0.18); border-color: rgba(var(--danger-rgb), 0.5); color: var(--danger); }
.stage-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.stage-btn:active:not(:disabled) { transform: scale(0.93); }


/* Kid detail panel — freshly inserted into the DOM each time a row expands
   (see onSchoolsClick/onCampsClick), so a plain CSS `animation` (which plays
   automatically on insertion) gives a smooth open with no JS changes needed. */
.kid-detail {
  padding: 4px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  animation: kidDetailOpen 0.4s ease;
  transform-origin: top;
}
.kid-detail.hidden { display: none; }
@keyframes kidDetailOpen {
  0% { opacity: 0; transform: scaleY(0.96) translateY(-4px); }
  100% { opacity: 1; transform: scaleY(1) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .kid-detail { animation: none; }
}

.alert-box {
  padding: 9px 12px;
  border-radius: 12px;
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.4;
}
.alert-box.allergy { background: rgba(var(--danger-rgb), 0.14); border: 1px solid rgba(var(--danger-rgb), 0.4); border-left: 4px solid var(--danger); color: var(--danger-text); }
.alert-box.needs { background: rgba(var(--warn-rgb), 0.14); border: 1px solid rgba(var(--warn-rgb), 0.4); border-left: 4px solid var(--warn); color: var(--warn-text); }
.alert-box.schedule { background: rgba(var(--lavender-rgb), 0.14); border: 1px solid rgba(var(--lavender-rgb), 0.4); border-left: 4px solid var(--lavender); color: var(--lavender-text); }
.alert-box.contact { background: rgba(var(--accent-rgb), 0.14); border: 1px solid rgba(var(--accent-rgb), 0.4); border-left: 4px solid var(--accent); color: var(--accent-text); font-weight: 600; }
.schedule-box { display: flex; flex-direction: column; gap: 4px; }
/* Upcoming drop-in dates for this kid — accent-tinted, distinct from the
   lavender weekly schedule box above it. */
.alert-box.schedule.drop-in-schedule {
  background: rgba(var(--accent-rgb), 0.12);
  border: 1px solid rgba(var(--accent-rgb), 0.4);
  border-left: 4px solid var(--accent);
  color: var(--accent-text);
  margin-top: 6px;
}
.alert-box.pickup { background: rgba(var(--blue-rgb), 0.1); border: 1px solid rgba(var(--blue-rgb), 0.35); border-left: 4px solid var(--blue); color: var(--blue-text); }
.alert-box.dob { background: rgba(148, 163, 184, 0.12); border: 1px solid var(--card-border); border-left: 4px solid var(--text-dim); color: var(--text-dim); font-weight: 600; }
.alert-box.birthday { background: rgba(var(--accent-rgb), 0.22); border: 1px solid rgba(var(--accent-rgb), 0.55); border-left: 4px solid var(--accent); color: var(--accent-text); font-weight: 800; }

.notes-section-title { margin: 4px 0 0; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-dim); font-weight: 700; }
.notes-timeline { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; max-height: 200px; overflow-y: auto; }
.note-item { background: var(--bg-alt); border-radius: 10px; padding: 8px 10px; font-size: 0.82rem; }
.note-item.event .note-text { color: var(--blue); font-weight: 600; }
.notes-empty { font-size: 0.78rem; color: var(--text-dim); padding: 4px 2px; }

.add-note-row { display: flex; gap: 8px; }
.add-note-input {
  flex: 1;
  padding: 9px 12px;
  border-radius: 10px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  color: var(--text);
  font-size: 0.82rem;
}
.add-note-input:focus { outline: 2px solid var(--blue); }

.card-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 2px; }

/* History — a dropdown-within-the-dropdown on a Profile's detail panel.
   Starts collapsed and resets shut whenever the kid's own row collapses
   (see historyExpanded in app.js), so History never stays open across a
   fresh expand. */
.history-toggle {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  width: 100%;
  background: none;
  border: none;
  padding: 4px 0 0;
  margin: 0;
  cursor: pointer;
  text-align: left;
}
.history-toggle .notes-section-title { margin: 0; }
.history-toggle-caret {
  color: var(--text-dim);
  font-size: 0.72rem;
  transition: transform 0.2s ease;
}
.history-toggle.open .history-toggle-caret { transform: rotate(180deg); }
.history-body.hidden { display: none; }
.history-body:not(.hidden) { animation: kidDetailOpen 0.4s ease; }

/* Per-child history calendar — Profiles tab only. Each day cell is colored
   by that day's furthest-reached status (absent > picked up > checked in >
   bus confirmed), pulled from state.history for past days or the kid's
   live bus/in/out for today. */
.calendar-block {
  background: var(--bg-alt);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 10px;
}
.cal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.cal-month-label { font-size: 0.82rem; font-weight: 700; color: var(--text); }
.cal-nav {
  width: 26px; height: 26px;
  border-radius: 8px;
  border: 1px solid var(--card-border);
  background: var(--card);
  color: var(--text);
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
}
.cal-nav:hover { background: rgba(var(--blue-rgb), 0.15); }

.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.cal-dow { text-align: center; font-size: 0.62rem; font-weight: 700; color: var(--text-dim); text-transform: uppercase; padding: 2px 0; }
.cal-cell {
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--card);
  color: var(--text-dim);
  font-size: 0.68rem;
  font-weight: 500;
  cursor: pointer;
  padding: 0;
}
.cal-cell.cal-empty { background: transparent; border: none; cursor: default; }
.cal-cell .cal-mark { font-size: 0.62rem; line-height: 1; }
.cal-cell.cal-today { border-color: var(--blue); }
.cal-cell.cal-selected { outline: 2px solid var(--blue); outline-offset: 1px; }
.cal-cell.cal-bus { background: rgba(var(--blue-rgb), 0.18); color: var(--blue-text); }
.cal-cell.cal-in { background: rgba(var(--accent-rgb), 0.2); color: var(--accent-text); }
.cal-cell.cal-out { background: rgba(var(--accent-rgb), 0.35); color: var(--accent-text); }
.cal-cell.cal-absent { background: rgba(var(--danger-rgb), 0.2); color: var(--danger-text); }
/* Drop-in day — dashed accent ring, composes over any check-in status fill. */
.cal-cell.cal-dropin { box-shadow: inset 0 0 0 2px rgba(var(--accent-rgb), 0.85); }

.cal-day-detail { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--card-border); }
.cal-hint { margin: 0; font-size: 0.76rem; color: var(--text-dim); }
.cal-detail-date { margin: 0 0 2px; font-size: 0.8rem; font-weight: 700; color: var(--text); }
.cal-detail-stages { display: flex; gap: 8px; margin: 6px 0 10px; }
.cal-detail-stages .stage-btn { width: 40px; height: 40px; }
.cal-comments { margin: 0; padding-left: 18px; font-size: 0.78rem; color: var(--text); }
.cal-comments li { margin-bottom: 2px; }

/* ---- Attendance tab (admin only) ---- */
.attendance-view { margin-top: 10px; }
.att-toggle {
  display: flex; gap: 4px; margin: 0 0 12px;
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: 10px; padding: 3px; max-width: 220px;
}
.att-tab {
  flex: 1; border: none; background: transparent; color: var(--text-dim);
  font-weight: 700; font-size: 0.8rem; padding: 6px 4px; border-radius: 7px; cursor: pointer;
}
.att-tab.active { background: var(--blue); color: var(--on-accent); }

/* Month calendar — reuses .calendar-block / .cal-* ; a cell shows a headcount */
.att-cal .cal-cell { color: var(--text-dim); }
.att-cal .cal-cell .cal-daynum { font-size: 0.7rem; font-weight: 600; }
.att-cell .att-count {
  font-size: 0.95rem; font-weight: 800; line-height: 1;
  color: var(--accent-text);
}
.att-cell .att-count:empty { display: none; }
.att-cell.att-zero .att-count { color: var(--text-dim); opacity: 0.5; }
.att-cell:not(:disabled):not(.cal-selected):hover { border-color: var(--blue); }
.att-cell.att-weekend, .att-cell.att-future {
  background: transparent; color: var(--text-dim); cursor: default;
}
.att-cell.att-weekend .cal-daynum, .att-cell.att-future .cal-daynum { opacity: 0.4; }
.att-month-total {
  margin: 10px 0 0; padding-top: 8px; border-top: 1px solid var(--card-border);
  font-size: 0.76rem; color: var(--text-dim); text-align: center;
}

/* Day list */
.att-day-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.att-day-label { font-size: 0.9rem; font-weight: 800; color: var(--text); text-align: center; flex: 1; }
.att-today-link {
  display: block; margin: 8px auto 0; border: none; background: none;
  color: var(--blue); font-weight: 700; font-size: 0.78rem; cursor: pointer;
}
.att-summary {
  margin: 12px 0 4px; padding: 10px 12px;
  background: var(--bg-alt); border: 1px solid var(--card-border); border-radius: 10px;
  font-size: 0.82rem; color: var(--text-dim);
}
.att-summary strong { color: var(--text); font-size: 0.95rem; }
.att-group { margin-top: 14px; }
.att-group-name {
  margin: 0 0 6px; font-size: 0.72rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-dim);
}
.att-row {
  display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 10px;
  padding: 9px 4px; border-bottom: 1px solid var(--card-border);
}
.att-row:last-child { border-bottom: none; }
.att-row-name { font-size: 0.86rem; font-weight: 600; color: var(--text); }
.att-row-prog { font-size: 0.74rem; color: var(--text-dim); text-align: right; }
.att-dropin {
  font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--accent-text); background: rgba(var(--accent-rgb), 0.18);
  border-radius: 5px; padding: 1px 5px; margin-left: 4px; vertical-align: 1px;
}
.att-pill {
  font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em;
  border-radius: 999px; padding: 3px 9px; white-space: nowrap;
}
.att-pill.is-in { background: rgba(var(--accent-rgb), 0.2); color: var(--accent-text); }
.att-pill.is-out { background: rgba(var(--accent-rgb), 0.38); color: var(--accent-text); }
.att-pill.is-bus { background: rgba(var(--blue-rgb), 0.18); color: var(--blue-text); }
.att-pill.is-away { background: rgba(var(--danger-rgb), 0.2); color: var(--danger-text); }
.att-pill.is-none { background: var(--card); color: var(--text-dim); border: 1px solid var(--card-border); }

/* ---- Account modal: admin "View as" role preview ---- */
.account-preview { margin-top: 4px; }
.acct-seg {
  display: flex; gap: 4px; margin-top: 4px;
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: 10px; padding: 3px;
}
.acct-seg-btn {
  flex: 1; border: none; background: transparent; color: var(--text-dim);
  font-weight: 700; font-size: 0.78rem; padding: 7px 4px; border-radius: 7px; cursor: pointer;
  white-space: nowrap;
}
.acct-seg-btn.active { background: var(--blue); color: var(--on-accent); }
/* Header button while a preview is active — matches Demo Mode's "temporary" look */
#account-btn.is-previewing {
  background: rgba(var(--warn-rgb), 0.18);
  border-color: rgba(var(--warn-rgb), 0.5);
  color: var(--warn-text);
}

.roster-empty { text-align: center; color: var(--text-dim); font-size: 0.9rem; padding: 26px 0; }

/* Modal */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(6, 12, 22, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal-overlay.hidden { display: none; }
/* #confirm-modal is a generic "are you sure" dialog that can be triggered
   from inside another already-open modal (deleting a school/program from
   Manage, deleting a profile from the Edit Child modal) — it needs to
   always sit above every other modal, not just tie on z-index and depend
   on HTML source order to win (which is what let Manage render on top of
   it, since Manage happens to come later in the markup). */
#confirm-modal { z-index: 65; }
/* Opens after #confirm-modal has already closed (school deletion's second,
   code-gated step), but still needs to out-rank Manage for the same reason. */
#delete-school-code-modal { z-index: 65; }
/* Same story — these open from inside the already-open Manage modal. */
#school-edit-modal, #program-edit-modal, #camp-location-edit-modal { z-index: 65; }
.modal {
  width: 100%;
  max-width: 440px;
  max-height: 90vh;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.modal-narrow { max-width: 320px; }
.whoami-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid var(--border, rgba(148, 163, 184, 0.25));
}
.whoami { font-size: 0.8rem; color: var(--text-dim); }

/* Manage modal — After School / Camps tab selector */
.manage-tabs {
  display: flex; gap: 4px;
  background: var(--card); border: 1px solid var(--card-border);
  border-radius: 12px; padding: 4px; margin: 4px 0 14px;
}
.manage-tab {
  flex: 1; border: none; background: transparent;
  color: var(--text-dim); font-weight: 700; font-size: 0.85rem;
  padding: 9px 4px; border-radius: 9px; cursor: pointer;
}
.manage-tab.active { background: var(--blue); color: var(--on-accent); }
.manage-divider {
  height: 1px; margin: 18px 0 4px;
  background: var(--border, rgba(148, 163, 184, 0.25));
}
/* breathing room around the section labels in Manage */
#categories-modal .manage-tab-panel .field-label { display: block; padding: 16px 2px 18px; margin: 0; }
#categories-modal .manage-tab-panel .add-category-row + .field-label { margin-top: 16px; }
#categories-modal .manage-tab-panel .category-list { margin-top: 2px; }

/* collapsible Backup & data section */
.manage-advanced { margin-top: 6px; }
.manage-advanced > summary {
  cursor: pointer; list-style: none;
  font-size: 0.76rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-dim);
  padding: 9px 2px; display: flex; align-items: center; gap: 7px;
}
.manage-advanced > summary::-webkit-details-marker { display: none; }
.manage-advanced > summary::before {
  content: "▸"; font-size: 0.8em; transition: transform 0.15s ease;
}
.manage-advanced[open] > summary::before { transform: rotate(90deg); }
.manage-advanced-body { padding: 2px 0 6px; }
.manage-advanced-hint {
  margin: 0 0 10px; font-size: 0.76rem; line-height: 1.45;
  color: var(--text-dim); opacity: 0.85;
}

/* Manage modal: anchor to the top so switching After School <-> Camps grows
   or shrinks the box downward, keeping the tab bar in a fixed spot instead
   of re-centering the whole dialog. */
#categories-modal { align-items: flex-start; }
#categories-modal .modal {
  margin-top: 4vh;
  max-height: calc(100vh - 4vh - 44px);
  transition: none;
}

.gate-alt { margin: 12px 0 0; font-size: 0.82rem; color: var(--text-dim); text-align: center; }
.linkbtn {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--accent, #8ab4f8); font: inherit; font-size: inherit;
  text-decoration: underline; text-underline-offset: 2px;
}
.linkbtn:hover { opacity: 0.8; }
#request-done { color: #5fca8f; }

/* pending join requests */
.team-row.is-pending { border-color: #d8a13a; background: rgba(216, 161, 58, 0.08); }
.team-pending-badge {
  font-family: var(--cond, sans-serif); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; font-size: 0.62rem;
  color: #d8a13a; border: 1px solid #d8a13a; border-radius: 999px;
  padding: 1px 7px; margin-left: 6px; vertical-align: middle;
}
.team-section-label {
  font-family: var(--cond, sans-serif); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.08em; font-size: 0.72rem; color: var(--text-dim);
  margin: 4px 0 2px;
}
#team-btn.has-pending::after {
  content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: #d8a13a; margin-left: 5px; vertical-align: middle;
}

.team-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.team-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  border: 1px solid var(--border, rgba(148, 163, 184, 0.25));
  border-radius: 10px;
}
.team-row.is-disabled { opacity: 0.5; }
.team-row-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 7px; min-width: 0; }
.team-row-name { font-weight: 700; font-size: 0.9rem; }
.team-row-email { font-size: 0.76rem; color: var(--text-dim); word-break: break-all; }
.team-row-note { font-size: 0.7rem; color: var(--text-dim); font-style: italic; margin-top: -3px; }
.team-row-pending { font-size: 0.7rem; color: var(--text-dim); font-style: italic; }
.team-row-controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
.team-role-select { padding: 5px 8px; font-size: 0.78rem; }
.team-add { display: flex; flex-direction: column; gap: 8px; }
.team-add-row2 { display: flex; gap: 8px; }
.team-add-row2 select { flex: 1; }
.team-you { font-size: 0.68rem; color: var(--text-dim); }
.modal h2 { margin: 0 0 6px; font-size: 1.1rem; }
.modal-sub { margin: 0 0 10px; font-size: 0.82rem; color: var(--text-dim); }
.modal-error { color: var(--danger); font-size: 0.8rem; font-weight: 700; margin: 6px 0 0; }
.field-label { font-size: 0.76rem; font-weight: 700; color: var(--text-dim); margin: 10px 0 4px; }
.field-input {
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
}
.field-input:focus { outline: 2px solid var(--blue); }
.field-textarea { resize: vertical; min-height: 56px; }
.modal-actions { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-top: 16px; }
.modal-actions-right { display: flex; gap: 10px; margin-left: auto; }

.field-label-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 10px 0 4px; }
.field-label-row .field-label { margin: 0; }
.field-label-hint { font-weight: 400; text-transform: none; letter-spacing: normal; color: var(--text-dim); opacity: 0.8; }

.kv-add-btn {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 8px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  color: var(--blue);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.kv-add-btn:hover { background: rgba(var(--blue-rgb), 0.15); }
.kv-add-btn:active { transform: scale(0.93); }

.kv-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 4px; }
.kv-row { display: grid; grid-template-columns: 1fr 1fr 26px; gap: 6px; align-items: center; }
.kv-row .field-input { font-size: 0.85rem; padding: 8px 10px; }
.kv-remove {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 8px;
  border: 1px solid rgba(var(--danger-rgb), 0.35);
  background: transparent;
  color: var(--danger);
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
}
.kv-remove:hover { background: rgba(var(--danger-rgb), 0.1); }
.kv-empty { font-size: 0.72rem; color: var(--text-dim); padding: 0 2px 4px; margin-top: -4px; }

/* Extra Days list in the kid modal */
.extra-dates-list { display: flex; flex-direction: column; margin-bottom: 4px; }
.extra-date-add-row { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.extra-date-row { display: flex; align-items: center; gap: 8px; padding: 6px 2px; border-bottom: 1px solid var(--card-border); }
.extra-date-row:last-child { border-bottom: none; }
.extra-date-label { flex: 1; font-size: 0.82rem; }
.extra-date-row.is-past .extra-date-label { color: var(--text-dim); }
.extra-date-past { font-size: 0.7rem; color: var(--text-dim); }

.note-row { display: grid; grid-template-columns: 1fr 28px; gap: 6px; align-items: stretch; }
.note-row .field-textarea { min-height: 46px; font-size: 0.85rem; padding: 8px 10px; }
.note-actions { display: flex; flex-direction: column; gap: 4px; }
.note-actions button {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border-radius: 8px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  color: var(--text-dim);
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
}
.note-actions button:hover:not(:disabled) { background: rgba(var(--blue-rgb), 0.15); }
.note-actions button:disabled { opacity: 0.3; cursor: not-allowed; }
.note-actions .note-remove { color: var(--danger); border-color: rgba(var(--danger-rgb), 0.35); font-size: 0.9rem; }
.note-actions .note-remove:hover:not(:disabled) { background: rgba(var(--danger-rgb), 0.1); }

@media (max-width: 420px) {
  .kv-row { grid-template-columns: 1fr; }
  .kv-remove { justify-self: end; }
}

.select-row { display: flex; gap: 6px; align-items: center; }
.select-row select, .select-row input { flex: 1; min-width: 0; }

.day-picker { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }

/* Date-of-birth wheel picker — three scroll-snap columns behaving like an
   iOS drum on touch and scroll-and-snap with the mouse wheel on desktop.
   Row height 34px, 5 rows visible (170px), 68px spacer so the first/last
   real item can sit in the centre band. */
/* Collapsed summary that toggles the wheels open, keeping the modal sleek. */
.dob-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  text-align: left;
  font: inherit;
  color: var(--text);
  cursor: pointer;
}
.dob-summary .placeholder { color: var(--text-dim); }
.dob-summary-caret {
  flex-shrink: 0;
  color: var(--text-dim);
  font-size: 0.7rem;
  transition: transform 0.15s ease;
}
.dob-summary[aria-expanded="true"] .dob-summary-caret { transform: rotate(180deg); }

.wheel-picker[hidden] { display: none; }
.wheel-picker {
  position: relative;
  display: grid;
  grid-template-columns: 1.6fr 0.9fr 1.1fr;
  gap: 2px;
  height: 170px;
  min-height: 170px;
  margin-top: 6px;
  flex-shrink: 0; /* the modal is a flex column — don't let this collapse */
  border: 1px solid var(--card-border);
  border-radius: 10px;
  background: var(--bg-alt);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 32%, #000 68%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 32%, #000 68%, transparent);
}
.wheel {
  position: relative;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  text-align: center;
  outline: none;
  touch-action: pan-y;
}
.wheel::-webkit-scrollbar { display: none; }
.wheel:focus-visible { background: rgba(var(--blue-rgb), 0.08); }
.wheel-item {
  height: 34px;
  line-height: 34px;
  font-size: 0.9rem;
  scroll-snap-align: center;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  user-select: none;
}
.wheel-item.spacer { height: 68px; scroll-snap-align: none; pointer-events: none; }
.wheel-item.sel { color: var(--text); font-weight: 700; }
.wheel-band {
  position: absolute;
  left: 0; right: 0; top: 68px; height: 34px;
  border-top: 1px solid rgba(var(--blue-rgb), 0.4);
  border-bottom: 1px solid rgba(var(--blue-rgb), 0.4);
  pointer-events: none;
}
.day-pick-btn {
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  color: var(--text-dim);
  font-weight: 600;
  font-size: 0.82rem;
  cursor: pointer;
}
.day-pick-btn.selected { background: var(--blue); color: var(--on-accent); border-color: var(--blue); }

.program-day-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.program-day-tab {
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: transparent;
  color: var(--text-dim);
  font-weight: 600;
  font-size: 0.76rem;
  cursor: pointer;
}
.program-day-tab.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
/* A weekday tab that's here only because an Extra Day falls on it. */
.program-day-tab.extra-only { border-style: dashed; border-color: rgba(var(--accent-rgb), 0.6); }
.program-day-tab.extra-only.active { border-style: solid; }
.program-copy-all-btn { margin-top: 8px; }

.program-picker { display: flex; flex-wrap: wrap; gap: 8px; }

/* Split pill: left zone toggles selection, right zone (divided by a line)
   is a full-height edit button — deliberately large so it can't be hit by
   accident while tapping the pill to select/deselect a program. */
.program-pick-wrap {
  display: flex;
  align-items: stretch;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: var(--bg-alt);
  overflow: hidden;
}
.program-pick-wrap.selected { background: var(--blue); border-color: var(--blue); }

.program-pick-select {
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-weight: 600;
  font-size: 0.82rem;
  padding: 8px 14px;
  cursor: pointer;
}
.program-pick-wrap.selected .program-pick-select { color: var(--on-accent); }

.program-pick-order {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--on-accent);
  color: #fff;
  font-size: 0.65rem;
  font-weight: 800;
  margin-right: 5px;
}

/* Category management */
.category-list { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.category-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--bg-alt);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 7px 10px;
  font-size: 0.85rem;
  font-weight: 500;
}
.category-list button {
  background: transparent;
  border: none;
  color: var(--danger);
  font-weight: 700;
  cursor: pointer;
  font-size: 0.78rem;
}
.category-actions { display: flex; align-items: center; gap: 10px; }
.category-edit-btn { color: var(--text-dim) !important; font-size: 0.9rem !important; }
.add-category-row { display: flex; gap: 8px; }
.add-category-row .field-input { flex: 1; }

/* Toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: 72px;
  transform: translateX(-50%) translateY(20px);
  z-index: 70;
  background: linear-gradient(135deg, var(--blue), var(--accent));
  color: var(--on-accent);
  padding: 12px 20px;
  border-radius: 14px;
  font-weight: 700;
  font-size: 0.85rem;
  box-shadow: var(--shadow);
  opacity: 0;
  transition: all 0.35s ease;
  pointer-events: none;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

@media (max-width: 560px) {
  .grid-head-inner, .kid-row {
    grid-template-columns: 36px minmax(72px, 1fr) 72px 36px 36px 36px;
    gap: 3px;
    padding-left: 8px;
    padding-right: 8px;
  }
  .grid-head-inner > span { font-size: 0.62rem; letter-spacing: 0.02em; }
  .kid-row .stage-btn { width: 34px; height: 34px; }
  .grid-head-inner.profiles-mode, .kid-row.profile-row {
    grid-template-columns: minmax(80px, 0.8fr) 1.2fr;
  }
  .grid-head-inner.camp-location-mode, .kid-row.camp-location-mode {
    grid-template-columns: minmax(96px, 1fr) 86px 40px 40px;
  }
  .stage-btn { width: 38px; height: 38px; }
}
