/* ==========================================================================
   Unbound palette — sampled from FINAL Logo/Color with black outline.jpg

   Ryan, 2026-09-07: "Try to stick to the logo colors."

   The five logo colours are kept verbatim as --ub-ink/teal/green-logo/yellow/
   orange. Four of them are LIGHT: white text fails on every one (teal 2.32:1,
   green 1.51:1, orange 1.85:1, yellow 1.15:1), so the bright values are fills
   and spines only and darkened variants carry text. Every value below has its
   contrast measured, not guessed.

   Two deliberate departures, both recorded rather than buried:

   1. RED IS NOT IN THE LOGO. Samantha needs three instantly distinguishable
      urgency levels on the Rooms page — she specified the sort herself — and
      she used red in her own printed schedule for a class over its limit.
      Asked directly, she said: "I think leaving the urgent red is fine."
      The red is rotated to hue 10 so it sits in the same warm family as the
      logo orange instead of clashing pink against it.

   2. THE SUCCESS GREEN IS NOT THE LOGO GREEN. Darkened enough to carry text,
      the logo green lands at delta-E 5.6 from the warning amber under
      deuteranopia — indistinguishable to a red-green colour-blind reader, on
      exactly the pair that means "fine" versus "needs you". It is rotated
      toward the logo teal (hue 85 -> 157). --ub-green-logo keeps the true
      logo green for decorative use.

   Separation of the three room levels under deuteranopia: worst pair
   delta-E 33.1, carried by lightness as well as hue, and reinforced by border
   width (6px settled / 6px short / 10px hard floor) so colour is never the
   only channel.
   ========================================================================== */
:root {
  /* the logo, verbatim — fills and spines, never text */
  --ub-ink: #142223;
  --ub-teal: #15BCC9;
  --ub-green-logo: #A6E550;
  --ub-yellow: #FCF45C;
  --ub-orange: #FDAF1B;

  /* teal, darkened to carry text */
  --ub-teal-deep: #0B4A50;   /* filled buttons, dark surfaces; white 9.95:1 */
  --ub-teal-ink: #0B6269;    /* headings, emphasis; 7.08:1 on white */
  --ub-teal-link: #0E7A83;   /* links; 5.08:1 — replaces Bootstrap blue */
  --ub-teal-mid: #12A4AF;    /* focus rings, spines; 3.02:1 */
  --ub-teal-tint: #E4F6F8;
  --ub-teal-tint-deep: #CDEEF1;

  /* success — rotated toward teal, see note 2 above */
  --ub-green-ink: #127E55;   /* 5.07:1 on white */
  --ub-green-mid: #1FA873;   /* 3.04:1, non-text */
  --ub-green-tint: #E6F6EE;

  /* warning / awaiting her decision */
  --ub-amber-ink: #A16100;   /* 4.97:1 on white */
  --ub-amber-tint: #FFF3D6;
  --ub-amber-line: #F0D48A;
  --ub-yellow-tint: #FEFBD4; /* "today" only — never a status */

  /* urgent — her call, see note 1 above */
  --ub-red: #D93A1E;
  --ub-red-deep: #8C2114;    /* danger text; 8.96:1 */
  --ub-red-tint: #FDECEA;
  --ub-red-tint-deep: #FBDAD5;
  --ub-red-wash: #FFF7F5;
  --ub-red-line: #F2B3A6;

  /* quiet ground — mostly unchanged neutrals, so four saturated brand
     colours can read as signal rather than decoration */
  --ub-slate-400: #8FA0A3;
  --ub-slate: #6c757d;
  --ub-slate-dark: #495057;
  --ub-line: #dee2e6;
  --ub-line-soft: #e9ecef;
  --ub-surface: #ffffff;
  --ub-surface-2: #f8f9fa;
  --ub-surface-3: #fbfbfc;
  --ub-rule: rgba(20, 34, 35, .12);
  --ub-scrim: rgba(20, 34, 35, .5);
  --ub-shadow: rgba(20, 34, 35, .08);
}

/* Bootstrap's blue is the app's most common colour by accident, not by
   choice. Point its link and primary variables at the logo teal so every
   stock component follows the brand without being restyled one by one. */
:root {
  /* Bootstrap 5.3 builds link colour from the -rgb triple, so setting only
     --bs-link-color leaves every plain <a> on its stock blue. */
  --bs-link-color: var(--ub-teal-link);
  --bs-link-color-rgb: 14, 122, 131;
  --bs-link-hover-color: var(--ub-teal-ink);
  --bs-link-hover-color-rgb: 11, 98, 105;
  --bs-primary: var(--ub-teal-deep);
  --bs-primary-rgb: 11, 74, 80;
}

.btn-outline-primary {
  --bs-btn-color: var(--ub-teal-ink);
  --bs-btn-border-color: var(--ub-teal-mid);
  --bs-btn-hover-bg: var(--ub-teal-deep);
  --bs-btn-hover-border-color: var(--ub-teal-deep);
  --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: var(--ub-ink);
  --bs-btn-active-border-color: var(--ub-ink);
  --bs-btn-disabled-color: var(--ub-teal-ink);
  --bs-btn-disabled-border-color: var(--ub-teal-mid);
}

.btn-primary {
  --bs-btn-bg: var(--ub-teal-deep);
  --bs-btn-border-color: var(--ub-teal-deep);
  --bs-btn-hover-bg: var(--ub-ink);
  --bs-btn-hover-border-color: var(--ub-ink);
  --bs-btn-active-bg: var(--ub-ink);
  --bs-btn-active-border-color: var(--ub-ink);
  --bs-btn-disabled-bg: var(--ub-teal-deep);
  --bs-btn-disabled-border-color: var(--ub-teal-deep);
}

.btn-outline-secondary {
  --bs-btn-color: var(--ub-teal-ink);
  --bs-btn-border-color: var(--ub-line);
  --bs-btn-hover-bg: var(--ub-teal-tint);
  --bs-btn-hover-border-color: var(--ub-teal-mid);
  --bs-btn-hover-color: var(--ub-teal-ink);
}

/*
 * app.css - Unbound Homeschoolers site styles.
 *
 * This is a small companion sheet layered on top of the Bootstrap 5.3 CDN
 * build loaded in base.html. Keep it short: it exists for a handful of
 * tweaks Bootstrap's utility classes don't cover on their own, not as a
 * place to re-theme the app.
 *
 * Currently just navbar polish: the top nav has 12+ links, so it always
 * lives behind the collapse/hamburger toggle (see base.html) rather than
 * trying to fit inline at any width. These rules make that collapsed menu
 * comfortable to read and tap.
 */

.navbar-nav .nav-link {
  padding-top: .6rem;
  padding-bottom: .6rem;
}

.navbar-collapse .nav-item + .nav-item {
  border-top: 1px solid rgba(255, 255, 255, .08);
}

/* The toggler sits at the top right, so the menu opens there too.
 * Full-width and left-aligned meant clicking the button on the right and then
 * travelling the whole screen to pick an item — Samantha asked for the list to
 * stay under the button (2026-09-07). Anchored to the right edge on anything
 * wider than a phone; full width below that, where there is nowhere else to go. */
@media (min-width: 576px) {
  .navbar > .container-fluid {
    position: relative;
  }

  .navbar-collapse#navbarNav {
    position: absolute;
    top: 100%;
    right: 0;
    z-index: 1030;
    width: 18rem;
    max-height: calc(100vh - 4.5rem);
    overflow-y: auto;
    background-color: var(--bs-dark, #212529);
    border: 1px solid rgba(255, 255, 255, .12);
    border-radius: .5rem;
    box-shadow: 0 .75rem 1.5rem rgba(0, 0, 0, .4);
    padding: .35rem 0;
  }

  .navbar-collapse#navbarNav .navbar-nav {
    padding-left: .5rem;
    padding-right: .5rem;
  }
}

/*
 * Parent-facing live meeting board (live_join.html / live_board.html /
 * live_ended.html, driven by static/js/live.js). Phone-first: 90% of this
 * view's use is a parent's phone in a library room, so tap targets and text
 * size are tuned for a ~390px screen first, then allowed to breathe on
 * anything wider. Read-only throughout - nothing here is styled to look
 * draggable or editable (see docs/LIVE_BOARD_CONTRACT.md).
 */
.live-narrow {
  max-width: 720px;
  padding-top: 1rem;
  padding-bottom: 2rem;
}

.live-badge {
  font-weight: 600;
  letter-spacing: .03em;
}

.live-centered-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
}

/* Naive review flagged the join screen's empty lower two-thirds as looking
   unfinished/half-loaded on a phone - give the card some vertical presence
   instead of leaving it pinned to the top of a tall, otherwise-empty page. */
#join-section {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
}

.live-join-card {
  width: 100%;
  max-width: 420px;
}

.live-ended-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background: var(--ub-green-tint);
  color: var(--ub-green-ink);
  font-size: 1.75rem;
  margin-left: auto;
  margin-right: auto;
}

.live-reconnect-hint {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--ub-amber-tint);
  color: var(--ub-amber-ink);
  font-size: .8rem;
  text-align: center;
  padding: .35rem .5rem;
  border-radius: .375rem;
  margin-bottom: .75rem;
}

/* Personal strip: always visible, so it stays pinned above whichever view
   (tabbed hours or the all-hours grid) is currently scrolled. */
.personal-strip {
  position: sticky;
  top: 0;
  z-index: 15;
  background: #fff;
  border: 1px solid #dee2e6;
  border-radius: .5rem;
  padding: .6rem .75rem;
  margin-bottom: .75rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
}

.personal-strip-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .25rem .5rem;
  font-size: .95rem;
}

.personal-strip-hour {
  font-weight: 600;
  color: #495057;
}

.personal-strip-value {
  font-weight: 700;
}

.personal-strip-sep {
  color: #adb5bd;
}

.personal-strip-class .personal-strip-value {
  color: var(--ub-green-ink);
}

.personal-strip-off .personal-strip-value {
  color: #6c757d;
}

.personal-strip-unassigned .personal-strip-value {
  color: var(--ub-red-deep);
}

.live-identity-row {
  text-align: right;
  margin: 0 0 .5rem;
}

.live-identity-row .btn-link {
  font-size: .8rem;
  text-decoration: underline;
}

.live-hour-note {
  font-size: .9rem;
  font-weight: 600;
  border-radius: .5rem;
  padding: .5rem .75rem;
  margin-bottom: .6rem;
}

.live-hour-note-off {
  background: #e9ecef;
  color: #495057;
}

.live-hour-note-unassigned {
  background: var(--ub-red-tint);
  color: var(--ub-red-deep);
}

.live-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .75rem;
}

.live-hour-tabs .nav-link {
  padding: .55rem 1rem;
  font-weight: 600;
}

.live-all-hours-switch {
  white-space: nowrap;
}

.live-hour-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: .6rem;
}

@media (min-width: 700px) {
  .live-hour-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.live-class-card {
  border: 1px solid #ced4da;
  border-left: 4px solid var(--ub-teal);
  background: #fff;
  border-radius: 0 .5rem .5rem 0;
  padding: .65rem .8rem;
}

.live-class-card-empty-state {
  border-left-color: #dee2e6;
  background: #fbfbfc;
}

.live-class-card-mine {
  border-left-color: var(--ub-green-mid);
  background: var(--ub-green-tint);
}

.live-class-card-group {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #6c757d;
  margin-bottom: .2rem;
}

.live-class-card-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}

.live-class-card-title {
  font-weight: 700;
  font-size: 1.05rem;
}

.live-you-badge {
  flex-shrink: 0;
  font-size: .75rem;
}

.live-class-card-teachers {
  font-size: .9rem;
  color: #343a40;
  margin-top: .2rem;
}

.live-class-card-empty {
  font-size: .9rem;
  color: var(--ub-slate);
  font-style: italic;
}

.live-class-card-need {
  font-size: .78rem;
  color: var(--ub-amber-ink);
  margin-top: .3rem;
}

.live-all-hours-wrap {
  margin-top: .25rem;
}

.live-all-hours-hint {
  font-size: .78rem;
  color: #6c757d;
  text-align: center;
  margin-bottom: .35rem;
}

/* A phone's webkit scrollbar auto-hides until touched, so a table that
   overflows to the right otherwise gives no clue there's more off-screen -
   see -all-hours-hint above for the text cue, and keep a visible (if thin)
   scrollbar here as a second, wordless one. */
.live-all-hours-scroll {
  scrollbar-width: thin;
}

.live-all-hours-scroll::-webkit-scrollbar {
  height: 6px;
}

.live-all-hours-scroll::-webkit-scrollbar-thumb {
  background: #adb5bd;
  border-radius: 3px;
}

.live-all-hours-table {
  font-size: .82rem;
  /* separate (not Bootstrap's default collapsed) borders, or the sticky
     first column below shows a 1px sliver of whatever scrolls underneath it
     at its trailing edge in Chromium. */
  border-collapse: separate;
  border-spacing: 0;
}

.live-all-hours-table th,
.live-all-hours-table td {
  white-space: nowrap;
  vertical-align: middle;
}

.live-all-hours-table th.live-all-hours-hour,
.live-all-hours-table th.live-all-hours-corner {
  position: sticky;
  left: 0;
  background: #f8f9fa;
  z-index: 2;
}

.live-all-hours-table td.live-all-hours-off {
  background: #fbfbfc;
}

/* Bold alone read as an unexplained/arbitrary highlight in review - color it
   the same green used for "You" everywhere else on the board (the badge, the
   personal strip's class-hour value), so it reads as the same "this one is
   you" language the viewer has already seen rather than a new, unglossed one. */
.live-all-hours-table strong {
  color: var(--ub-green-ink);
}

/*
 * Attendance — Merrilee's page (docs/ATTENDANCE_CONTRACT.md). Phone-first:
 * everything below is designed at 390px, and 44px is the tap-target floor
 * throughout (a thumb in a hallway, not a mouse pointer). The rest of the
 * app's cards/lists are laptop-first, so this section carries its own
 * tap-target and spacing rules rather than borrowing theirs.
 */
.attendance-page {
  max-width: 720px;
  margin: 0 auto;
}

.attendance-tap {
  min-height: 44px;
}

.attendance-back-link {
  display: inline-block;
  font-size: .85rem;
  color: #6c757d;
  text-decoration: none;
  margin-bottom: .15rem;
}

.attendance-section {
  margin-bottom: 1.75rem;
}

.attendance-section-title {
  margin-bottom: .6rem;
}

/* Loud vs quiet — rule 2: a child's absence is a note, an adult's absence
   opens a gap, and the screen must make that difference visible at a glance. */
.attendance-loud-out {
  display: inline-block;
  font-weight: 700;
  color: var(--ub-red-deep);
  background: var(--ub-red-tint);
  border-radius: 999px;
  padding: .1rem .55rem;
  margin: 0 .25rem .25rem 0;
  font-size: .85rem;
}

.attendance-quiet-out {
  color: #6c757d;
  font-size: .8rem;
}

.attendance-family-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.attendance-family-card {
  background: #fff;
  border: 1px solid #dee2e6;
  border-radius: .5rem;
  overflow: hidden;
}

/* Samantha, 2026-09-07, on the Who's out list on her phone: "these still
   don't line up nice." This row was a flex line with wrapping: name, status,
   caret and Undo took whatever space was left, so a long status pill pushed
   Undo onto a line of its own and every card broke differently — one card's
   Undo on the right, the next one's alone at the far left. Wrapping is what
   made it ragged, so the row is a grid now and every card lands in the same
   shape whatever its status says. */
.attendance-family-summary {
  width: 100%;
  min-height: 52px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  grid-template-areas: "name flags chevron undo";
  align-items: center;
  column-gap: .5rem;
  row-gap: .25rem;
  padding: .6rem .9rem;
  background: #fff;
  border: 0;
  text-align: left;
}

.attendance-family-summary-btn { grid-area: name; }
.attendance-family-flags { grid-area: flags; }
.attendance-family-chevron { grid-area: chevron; }
.attendance-family-undo { grid-area: undo; }

/* Who's out carries a sentence-length status ("Milagros out all morning")
   plus a child count, which will never share a line with the name on a
   phone. It gets its own line instead of being wrapped there by accident:
   name at the left of line one, caret and Undo at its right, status at the
   left of line two — the same shape on every card. */
#section-who-out[data-view="out"] .attendance-family-summary {
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas:
    "name  chevron undo"
    "flags flags   flags";
}

#section-who-out[data-view="out"] .attendance-family-flags {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-start;
  text-align: left;
  column-gap: .6rem;
  row-gap: .15rem;
}

.attendance-family-name {
  font-weight: 600;
  /* Take the free space so the status and the chevron pack to a fixed right
     edge. With space-between and three children the status sat in whatever
     gap the family name left over, so it drifted a little on every row.
     Samantha, 2026-09-07, drawing a line down the ragged edge: "These don't
     line up". */
  flex: 1 1 auto;
  min-width: 0;
}

.attendance-family-detail {
  padding: 0 .9rem .55rem;
  border-top: 1px solid #eee;
}

/* Samantha, 2026-09-07: "let's also find a way to make a single family
   viewable on one scroll on the phone. The mark out button could move over so
   it's not directly under the name." Then: "I think our biggest family is 8
   kids, so you need to be able to see up to 9 people on a single phone scroll
   if possible without making the text too small to view."

   So a person and their control share a line at every width. The height came
   from stacking name-above-button, not from the type size, which is untouched.
   The one thing that still needs its own line on a phone is a teaching
   parent's hour chips — four of them will not fit beside a name at 390px. */
.attendance-person-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: .5rem;
  row-gap: .2rem;
  /* The 44px tap target is the floor and stays. The padding around it is not,
     and nine of them is what decides whether an eight-child family fits on
     one phone screen. */
  padding: .1rem 0;
  border-bottom: 1px dashed #eee;
}

.attendance-person-row:last-child {
  border-bottom: none;
}

.attendance-person-name {
  font-weight: 600;
  font-size: .9rem;
  margin-bottom: 0;
}

.attendance-person-row > *:not(.attendance-person-name) {
  grid-column: 2;
  justify-self: end;
}

.attendance-hour-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
}

/* Written as a child selector so it outweighs the "everything but the name
   goes in column 2" rule above. It did not, and a teaching parent's four
   chips sized the auto column to their own width, collapsing the name column
   to nothing and printing the chips over her name. Samantha, 2026-09-07:
   "there is overlapping info." */
.attendance-person-row > .attendance-hour-chips {
  grid-column: 1 / -1;
  justify-self: stretch;
}

.attendance-chip {
  min-height: 44px;
  padding: .35rem .7rem;
  border-radius: 999px;
  border: 1px solid #ced4da;
  background: #f8f9fa;
  font-size: .85rem;
}

.attendance-chip-morning {
  border-style: dashed;
}

.attendance-chip-absent {
  background: var(--ub-red-tint);
  border-color: var(--ub-red-line);
  color: var(--ub-red-deep);
}

/* Rooms — short rooms are unmistakable across a room, per the contract
   ("unmistakable across a room" is a physical-distance requirement, not just
   a color-contrast one — hence the thick left border, not just a tint). */
.attendance-room-list {
  display: flex;
  flex-direction: column;
  gap: .6rem;
}

.attendance-room-card {
  background: #fff;
  border: 1px solid #dee2e6;
  border-left: 6px solid var(--ub-slate-400);
  border-radius: 0 .5rem .5rem 0;
  padding: .7rem .9rem;
}

.attendance-room-short {
  border-left-color: var(--ub-red);
  background: var(--ub-red-wash);
}

.attendance-room-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: .5rem;
}

.attendance-room-title-block {
  min-width: 0;
  flex: 1 1 auto;
}

.attendance-room-hour {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #6c757d;
}

/* Round 4 finding #2: "2/2" with one caption underneath ("adults") read as
   an unlabeled ratio — a reviewer couldn't tell which digit was which, and
   for an overstaffed room ("5/2") guessed the two numbers might even be two
   different groups (adults vs. children). Each number now carries its own
   word directly under it ("present" / "required" — the contract's own
   terms), so the mapping can't be misread regardless of which side is
   bigger, and it never claims two groups where there is only one (adults,
   in two states). Flex row of two labelled parts, same total height as the
   old fraction-plus-caption, so cards don't grow taller. */
.attendance-room-count {
  display: flex;
  align-items: baseline;
  gap: .2rem;
  flex-shrink: 0;
}

.attendance-room-count-part {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
}

.attendance-room-count-num {
  font-weight: 700;
  font-size: 1.1rem;
}

.attendance-room-count-tag {
  font-size: .58rem;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: inherit;
  opacity: .75;
  margin-top: .1rem;
}

.attendance-room-count-slash {
  font-weight: 700;
  font-size: 1.1rem;
  color: #adb5bd;
  align-self: flex-start;
}

/* Only the PRESENT half turns red when short — it's the number that's
   wrong, not the required count next to it. */
.attendance-room-count-short .attendance-room-count-part:first-child .attendance-room-count-num,
.attendance-room-count-short .attendance-room-count-part:first-child .attendance-room-count-tag {
  color: var(--ub-red-deep);
  opacity: 1;
}

.attendance-room-teachers {
  list-style: none;
  margin: .5rem 0 0;
  padding: 0;
  font-size: .85rem;
}

.attendance-teacher-gone {
  text-decoration: line-through;
  color: #6c757d;
}

.attendance-teacher-covering {
  color: var(--ub-green-ink);
}

.attendance-mini-undo {
  border: 0;
  background: none;
  color: #6c757d;
  font-size: .75rem;
  text-decoration: underline;
  padding: 0 0 0 .35rem;
}

.attendance-room-children-out {
  margin-top: .5rem;
  font-size: .8rem;
  color: #6c757d;
}

.attendance-short-filter {
  font-size: .85rem;
  display: flex;
  align-items: center;
  gap: .35rem;
}

.attendance-overlay {
  position: fixed;
  inset: 0;
  z-index: 1060;
  background: var(--ub-scrim);
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

@media (min-width: 576px) {
  .attendance-overlay {
    align-items: center;
  }
}

.attendance-overlay-panel {
  width: 100%;
  max-width: 480px;
  max-height: 80vh;
  overflow-y: auto;
  background: #fff;
  border-radius: .75rem .75rem 0 0;
  padding: 1rem;
}

@media (min-width: 576px) {
  .attendance-overlay-panel {
    border-radius: .75rem;
  }
}

.attendance-bench-list {
  list-style: none;
  margin: .5rem 0 0;
  padding: 0;
}

.attendance-bench-name {
  width: 100%;
  min-height: 48px;
  text-align: left;
  background: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: .5rem;
  padding: .5rem .75rem;
  margin-bottom: .4rem;
}

.attendance-guest-form {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.attendance-guest-form input,
.attendance-guest-form select {
  flex: 1 1 160px;
  min-width: 0;
}

/* A naive-reviewer pass (2026-09-07) flagged the family select truncating
   to "Not visiting a p..." at 390px — the row had three fields fighting for
   width. Force it to its own line instead of shrinking its text away. */
.attendance-guest-form select {
  flex-basis: 100%;
}

/* Round 4 (also fix if cheap): "Find a sub by person" was a bare button
   with no context for why you'd use it over tapping a short room directly.
   Same flex-basis: 100% trick as the guest-family <select> above — forces
   the button-plus-hint block onto its own row instead of squeezing against
   the "Only rooms short" checkbox in the flex-wrap header. */
.attendance-guest-row {
  padding: .3rem 0;
  border-bottom: 1px dashed #eee;
  font-size: .9rem;
}

.attendance-inline-error {
  color: var(--ub-red-deep);
  background: var(--ub-red-tint);
  border-radius: .4rem;
  padding: .5rem .75rem;
  font-size: .85rem;
}

.attendance-stat-number {
  font-size: 2.2rem;
  font-weight: 700;
  line-height: 1;
}

.attendance-stat-label {
  color: #6c757d;
  font-size: .85rem;
  margin-top: .3rem;
}

/* Loud, persistent, impossible to miss by accident — the opposite of the
   "silence on success" rule, on purpose, per the contract. */
.attendance-save-banner {
  position: sticky;
  top: 0;
  z-index: 1070;
  background: var(--ub-red);
  color: #fff;
  padding: .6rem 1rem;
  border-radius: .4rem;
  margin-bottom: .75rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.attendance-day-today {
  background: var(--ub-yellow-tint);
}

/*
 * Round 2 (2026-09-07) — findings from two context-blind phone screenshots
 * (docs/ATTENDANCE_CONTRACT.md unchanged; this is presentation only).
 * Append-only per CLAUDE.md's file-ownership rule for this pass: every rule
 * below is new, and where a fix needed to change how an existing selector
 * renders, it wins by matching cascade order (equal specificity, later in
 * the file) rather than editing the original rule in place.
 */

/* Finding #6: family rows had no tap affordance and no way to close the open
   panel except tapping the row again. ".attendance-family-summary" used to
   BE the single clickable button; it is now a flex wrapper around this
   button plus a sibling "Undo" control (never nested — two buttons inside
   one <button> is invalid HTML and breaks independent click targets). */
.attendance-family-summary-btn {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  background: none;
  border: 0;
  padding: 0;
  text-align: left;
  min-height: 44px;
}

.attendance-family-chevron {
  color: #6c757d;
  flex-shrink: 0;
  transition: transform .15s ease;
}

.attendance-family-chevron-open {
  transform: rotate(180deg);
}

.attendance-family-undo {
  flex-shrink: 0;
  border: 0;
  background: none;
  color: var(--ub-teal-link);
  font-weight: 600;
  font-size: .85rem;
  padding: 0 .9rem 0 .35rem;
  min-height: 44px;
}

/* Findings #1/#2/#7: the flags area now stacks distinct facts instead of
   running them together on one line — #7's exact complaint was an adult's
   gap and a child count crammed onto one line ("Ingrid — Hour 1  2 kids
   out") reading as a single sentence about two missing kids. */
.attendance-empty-note {
  font-size: .82rem;
  color: #6c757d;
  padding: .1rem .2rem .35rem;
  line-height: 1.35;
}

/* "all here" is a STATUS, not a control. Samantha tapped it expecting it to
   do something (2026-09-07: "I clicked on the all here spot thinking it would
   be a quick way to add all here"), and a cold reviewer independently could
   not tell whether it was a label or a button. It now reads as quiet state,
   and the chevron is the thing that looks like it opens the row. */
.attendance-family-flags .attendance-status-quiet {
  font-style: italic;
  color: #8a9298;
  font-size: .85rem;
}

.attendance-family-flags {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .2rem;
  flex: 0 0 auto;
  text-align: right;
}

/* Finding #1: labelled "Adults" / "Children" sections in the open family
   panel, so a mother is never mistaken for a child (or the reverse). */
.attendance-group-label {
  margin-top: .35rem;
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: #6c757d;
  margin: .6rem 0 .2rem;
}

/* Finding #3: the cover sheet's quiet explanatory line — the bench order,
   what a tap does, and that it is reversible, in one sentence. */
.attendance-overlay-subtitle {
  font-size: .85rem;
  color: #6c757d;
  margin: .25rem 0 .75rem;
}

/* Finding #11: a hard-floor room that is ALSO short is a legal-ratio
   problem, not just a scheduling gap — it must look heavier than a room
   that is merely short. Wins over the base card's border-left (equal
   specificity, later in the file) only when both apply. */
.attendance-room-hard-floor-short {
  border-left-width: 10px;
  border-left-color: var(--ub-red-deep);
  background: var(--ub-red-tint-deep);
}

/* Round 4 finding #3: "SAFETY MINIMUM" used to be a small red tag appended
   to EVERY hard-floor room's hour label whether or not anything was wrong —
   a fine, fully-staffed Nursery read as an active alarm. The note is now a
   real line of text (not CSS-generated content, so it reads correctly to
   screen readers too) with two distinct states: quiet/grey when the room is
   fine — it explains the rule, not a problem — and a bold red badge only
   when the room has actually dropped below the floor, matching the
   room-short styling used everywhere else on this page. */
.attendance-hard-floor-note {
  margin-top: .2rem;
  font-size: .72rem;
  color: #6c757d;
}

.attendance-hard-floor-note-alert {
  display: inline-block;
  margin-top: .3rem;
  font-weight: 700;
  font-size: .7rem;
  color: #fff;
  background: var(--ub-red-deep);
  border-radius: .25rem;
  padding: .1rem .45rem;
}

/* Finding #9: "Merrilee's numbers" read as a disabled button (grey outline).
   Restyled as an obvious, tappable secondary link — same label, same tap
   target size. */
.attendance-link-action {
  background: none;
  border: 0;
  color: var(--ub-teal-link);
  font-weight: 600;
  text-decoration: underline;
  padding: .3rem 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

/* Finding #4: names/dates under each stats card number. */
.attendance-stat-names {
  margin-top: .5rem;
  font-size: .85rem;
  color: #495057;
}

/* Finding #5: the second, less-common action (another date) is tucked under
   a labelled disclosure instead of competing with the one primary button. */
.attendance-other-date summary {
  cursor: pointer;
  color: var(--ub-teal-link);
  font-size: .85rem;
  min-height: 44px;
  display: flex;
  align-items: center;
}

/* Finding #12: "Nursery Room" wrapped awkwardly beside its ratio at 390px.
   Below that width the ratio drops beneath the title instead of fighting it
   for the same line. */
@media (max-width: 400px) {
  .attendance-room-header {
    flex-direction: column;
    align-items: flex-start;
    gap: .25rem;
  }
}

/*
 * Round 3 (2026-09-07) — findings from Merrilee's own persona run, reproduced
 * against current code and recorded in docs/QA_ROUND_3.md. Append-only per
 * CLAUDE.md's file-ownership rule for this pass, same convention round 2 used
 * above: new rules only, later-in-file wins where a selector needs to render
 * differently than its original definition.
 */

/* Finding #2/#3: the at-a-glance coverage summary. Sticky so re-checking it
   never costs a re-scroll past the family list (finding #3's "compounds
   everything"). Sits below the save banner in DOM order; the banner keeps a
   higher z-index so the rare case of both being stuck at once still shows
   the louder "not saved" state on top rather than the two fighting for the
   same pixels. */
.attendance-coverage-bar {
  position: sticky;
  top: 0;
  z-index: 1055;
  background: #fff;
  border: 1px solid #dee2e6;
  border-radius: .5rem;
  padding: .6rem .75rem;
  margin-bottom: 1.25rem;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .08);
}

.attendance-coverage-status {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  font-weight: 700;
  font-size: 1rem;
}

.attendance-coverage-ok {
  color: var(--ub-green-ink);
}

.attendance-coverage-short {
  color: var(--ub-red-deep);
}

.attendance-coverage-short::after {
  content: "— tap to view";
  font-weight: 400;
  font-size: .8rem;
  color: #6c757d;
  margin-left: .4rem;
}

.attendance-coverage-jumps {
  display: flex;
  gap: 1.1rem;
  margin-top: .3rem;
}

.attendance-jump-link {
  color: var(--ub-teal-link);
  text-decoration: none;
  font-weight: 600;
  font-size: .8rem;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
}

/* So an anchor jump (or the coverage summary's own scrollIntoView) lands the
   target heading below the sticky coverage bar instead of underneath it. */
.attendance-section {
  scroll-margin-top: 4.75rem;
}

/* Finding #1 (the serious one): a teaching parent must look different from
   everyone else in the Adults list before any tap, not just after. The blue
   left border and tint carry the same "unmistakable" intent the room-short
   left border already uses elsewhere on this page. */
.attendance-person-row-teaching {
  border-left: 4px solid var(--ub-teal-mid);
  padding-left: .6rem;
  background: var(--ub-teal-tint);
}

.attendance-person-row-bench {
  border-left: 4px solid transparent;
  padding-left: .6rem;
}

.attendance-teaches-badge {
  display: inline-block;
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--ub-teal-ink);
  background: var(--ub-teal-tint-deep);
  border-radius: 999px;
  padding: .1rem .5rem;
  margin-left: .3rem;
  vertical-align: middle;
}

.attendance-bench-only-badge {
  display: inline-block;
  font-size: .7rem;
  font-weight: 400;
  color: #6c757d;
  margin-left: .3rem;
  vertical-align: middle;
}

/* "Mark Danuta out:" sat above the chips as their label. With the chips on
   her own row it is a whole line repeating what "+ Hour 1" already says, and
   a line is what an eight-child family cannot spare. */
.attendance-person-subline {
  display: none;
}

/* An adult who teaches nothing today has no room gap to create, so their
   control is deliberately simpler than the teaching parent's pill-shaped
   hour-chip cluster — a single rectangular button, on purpose, so the two
   read as different controls even to a fast thumb. */
.attendance-plain-out {
  width: 100%;
  min-height: 44px;
  padding: .35rem .9rem;
  border-radius: .3rem;
  border: 1px solid #ced4da;
  background: #fff;
  font-size: .85rem;
}


/* Room to aim.

   Samantha, 2026-09-07, on the parent pool: "this panel of names needs a
   little breathing room so I can easily click the right parent." The pills
   were stacked with almost no gap, so on a laptop trackpad — never mind a
   phone — the wrong parent was an easy miss, and picking the wrong parent
   here drags the wrong person onto a class. Each name is now a comfortable
   target with real space between them. The pool scrolls inside itself, so
   this costs the board no height. */
.parent-sidebar .parent-chip {
  /* Split the difference. These were 24px and cramped, then 35px and
     "spread out too far" (Samantha, 2026-09-07) — this sits between the two
     and still clears a comfortable thumb. */
  padding: .3rem .6rem;
  margin: 0 0 .22rem 0;
  line-height: 1.3;
}

/* The quick links sit next to the hamburger, so they must not inherit the
   nav link colour that makes them vanish against the dark bar. */
.nav-quick-link {
  white-space: nowrap;
  padding-top: .15rem;
  padding-bottom: .15rem;
}

/* Every family gets marked.

   Samantha, 2026-09-07: "Because of how many families are present, I think it
   would be easy to think someone is present when they are not. Every family
   should need to be marked here." So presence is asserted, not assumed, and
   an unmarked family has to look unfinished rather than fine. */
.attendance-mark-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .1rem .2rem .45rem;
}

.attendance-mark-count {
  font-weight: 600;
  color: var(--ub-teal-ink);
}

.attendance-name-order {
  border: 1px solid #ced4da;
  background: #fff;
  border-radius: 999px;
  padding: .15rem .6rem;
  font-size: .82rem;
  color: #495057;
}

.attendance-here-btn {
  border: 1px solid var(--ub-green-ink);
  background: var(--ub-green-tint);
  color: var(--ub-green-ink);
  border-radius: 999px;
  padding: .25rem .75rem;
  font-weight: 600;
  font-size: .88rem;
  white-space: nowrap;
}

.attendance-here-done {
  border: 0;
  background: none;
  color: #6c757d;
  font-size: .84rem;
  white-space: nowrap;
  padding: .25rem 0;
}

.attendance-marked-toggle {
  width: 100%;
  border: 0;
  border-top: 1px solid #dee2e6;
  background: none;
  text-align: left;
  padding: .6rem .2rem .4rem;
  color: #6c757d;
  font-size: .88rem;
  margin-top: .5rem;
}

.attendance-all-marked {
  color: var(--ub-green-ink);
  background: var(--ub-green-tint);
  border-radius: 6px;
  padding: .6rem .75rem;
  margin: 0;
}


/* The chevron is now a real button (it opens the family panel, which "all
   here" beside it deliberately does not), so it needs to stop inheriting the
   default button box and go back to looking like a chevron. */
button.attendance-family-chevron {
  border: 0;
  background: none;
  color: #8a9298;
  font-size: 1rem;
  line-height: 1;
  padding: .35rem .4rem;
  flex: 0 0 auto;
}

button.attendance-family-chevron:hover {
  color: var(--ub-teal-ink);
}


/* The day's pages. These were anchors into one long scroll; they are separate
   pages now (Samantha: "Can we make it so the buttons bring you to a separate
   page, not just scroll down?"), so the current one has to say so. */
.attendance-jump-link.is-current {
  font-weight: 700;
  color: var(--ub-teal-ink);
  text-decoration: none;
  border-bottom: 2px solid var(--ub-teal-ink);
}


/* "the names are giant" (Samantha, 2026-09-07, on the Who's out page). The
   family name was inheriting the list's large tap-target sizing, which is
   right when the name IS the button on Mark attendance and far too heavy when
   you are reading down a page of open families. */
.attendance-family-name {
  font-size: .98rem;
}

/* A room whose absent teacher still leaves it on its required number is not
   short — but it is undecided, and Samantha was explicit that the site does
   not get to assume it is fine. Amber, not red: it needs her, it is not an
   emergency. */
.attendance-coverage-undecided {
  color: var(--ub-amber-ink);
  font-weight: 700;
}

.attendance-room-actions {
  display: flex;
  gap: .5rem;
  margin-top: .5rem;
}

.attendance-room-actions .btn {
  flex: 1 1 0;
}

.attendance-room-waived {
  margin-top: .5rem;
  padding: .45rem .6rem;
  border-radius: 6px;
  background: #eef1f3;
  color: #495057;
  font-size: .9rem;
}

.attendance-room-waive-undo {
  border: 0;
  background: none;
  color: var(--ub-teal-link);
  padding: 0;
  text-decoration: underline;
}

/* A confirm is a question, not a failure. It used to borrow the red
   error style, so "this will leave that room short — proceed?" looked
   like a refusal (Samantha, 2026-09-07: "it just errors"). */
.attendance-inline-confirm {
  background: var(--ub-amber-tint);
  border: 1px solid var(--ub-amber-line);
  border-radius: 6px;
  padding: .5rem .65rem;
  color: var(--ub-amber-ink);
  margin-top: .5rem;
}

.attendance-confirm-actions {
  display: flex;
  gap: .5rem;
  margin-top: .5rem;
}

.attendance-confirm-actions .btn {
  flex: 1 1 0;
}

/* A visitor added against a family puts that family back on the list to
   check — say so where she added them, so the effect is visible at the
   moment she causes it rather than only on another page. */
.attendance-guest-pending {
  display: inline-block;
  background: var(--ub-amber-tint);
  color: var(--ub-amber-ink);
  border-radius: 999px;
  padding: .05rem .5rem;
  font-size: .8rem;
  margin-left: .25rem;
}


/* Match the calendar page's section headings: small, uppercase, muted, with a
   hairline under them. Samantha wants attendance to read as the same site,
   not a separate app. */
.attendance-group-label {
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .72rem;
  font-weight: 700;
  color: #6c757d;
  border-bottom: 1px solid #e9ecef;
  padding-bottom: .2rem;
  margin-bottom: .35rem;
}

/* A tap has to look like it landed, even before the server answers. */
.attendance-pressed {
  outline: 2px solid var(--ub-teal-mid);
  outline-offset: 1px;
  background: var(--ub-teal-tint) !important;
  transition: background .05s ease;
}

.attendance-bench-name.attendance-pressed,
.attendance-family-summary-btn.attendance-pressed {
  background: var(--ub-teal-tint) !important;
}

/* Today's changes — the record of what Merrilee actually did. The rest of the
   day page shows what is still outstanding, so every problem she solves
   erases its own evidence. */
.attendance-summary-count {
  font-weight: 600;
  color: var(--ub-teal-ink);
}

.attendance-summary-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.attendance-summary-item {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding: .45rem .1rem;
  border-bottom: 1px solid #eef1f3;
}

.attendance-summary-kind {
  flex: 0 0 auto;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  border-radius: 999px;
  padding: .1rem .45rem;
  background: #eef1f3;
  color: #495057;
}

.attendance-summary-cover .attendance-summary-kind { background: #e4f6fa; color: #14707f; }
.attendance-summary-waive .attendance-summary-kind { background: #eef1f3; color: #5b6b73; }
.attendance-summary-out   .attendance-summary-kind { background: #fdecec; color: #a02a2a; }
.attendance-summary-guest .attendance-summary-kind { background: #eef8e6; color: #3f6b28; }

.attendance-summary-text { flex: 1 1 auto; }

.attendance-summary-at {
  flex: 0 0 auto;
  color: #8a9298;
  font-size: .8rem;
  white-space: nowrap;
}

/* The middle of Samantha's three levels: a teacher is out, the room still
   meets its number, and she has not yet said whether it needs a sub. Orange
   from the logo, and a wash rather than a shout — it needs her, it is not an
   emergency. */
.attendance-room-undecided {
  border-left-color: var(--ub-orange);
  background: var(--ub-amber-tint);
}


/* The colour bar is straight, not rounded off by the card's corner.
   Samantha, 2026-09-07, pointing at a pill from another site she uses: "I
   like the straight colored bar and the compactness of the information in
   each pill" — and then "you should change that curved bar to the straight
   one on every page please." A rounded card corner clips the top and bottom
   of the bar into a curve; squaring the left corners lets it read as a solid
   stripe down the edge. */

/* A number you can open. Samantha: "you should be able to click on these to
   get more info about the records we are keeping track of." */
.attendance-stat-detail > summary {
  cursor: pointer;
  color: var(--ub-teal-link);
  font-size: .9rem;
  padding: .15rem 0;
}

.attendance-stat-detail[open] > summary {
  color: var(--ub-teal-ink);
  font-weight: 600;
}

.attendance-stat-records {
  list-style: none;
  margin: .35rem 0 0;
  padding: 0;
  font-size: .88rem;
}

.attendance-stat-records li {
  padding: .25rem 0;
  border-top: 1px solid var(--ub-line-soft);
  color: var(--ub-slate-dark);
}

/* A prospective family here for the day, checked in like any other family but
   clearly not a member yet. */
.attendance-visiting-badge {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  background: var(--ub-teal-tint-deep);
  color: var(--ub-teal-ink);
  border-radius: 999px;
  padding: .05rem .4rem;
  margin-left: .35rem;
  vertical-align: middle;
}

/* Two out, one covered: say so. */
.attendance-room-gap-note {
  margin-top: .4rem;
  font-size: .88rem;
  font-weight: 600;
  color: var(--ub-amber-ink);
}

/* The two panel buttons used to be Bootstrap utilities (btn-lg, w-100). They
   are named now so the laptop block below can resize them without fighting
   w-100's !important. Phone shape is exactly what btn-lg + w-100 gave. */
.attendance-family-out-btn,
.attendance-family-close-btn {
  display: block;
  width: 100%;
}

/* This was btn-lg, which made the one destructive bulk action the biggest
   thing on the panel and cost a family with eight children the room to fit.
   Still full width and still a 44px target — just not oversized. */
.attendance-family-out-btn {
  font-size: 1rem;
  padding: .4rem 1rem;
  min-height: 44px;
  border-radius: .5rem;
}

/* ---------------------------------------------------------------------------
 * Laptop sizing for Merrilee's attendance page.
 *
 * Samantha, 2026-09-07: "these are just way too big for the computer. I have
 * to scroll sometimes just to hit close." Every rule above is drawn at 390px
 * with a 44px thumb floor, and the laptop simply inherited all of it, so one
 * open family filled her whole screen — a full-width btn-lg, then every person
 * as name-above-button, each button 44px tall.
 *
 * Phone-first is not weakened: nothing here applies below 768px. From there up
 * the pointer is a mouse, so a person and their controls sit on one line and
 * the tap floor drops to 32px. An open family goes from ~900px tall to ~320px,
 * which puts Close on screen without scrolling.
 * ------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .attendance-family-summary {
    min-height: 40px;
    padding: .3rem .75rem;
  }

  .attendance-family-detail {
    padding: .2rem .75rem .6rem;
  }

  .attendance-tap {
    min-height: 32px;
  }

  .attendance-chip,
  .attendance-plain-out {
    min-height: 30px;
    padding: .15rem .6rem;
    font-size: .82rem;
  }

  /* Wider than a phone: the name gets a fixed column and the chips come up
     beside it rather than dropping to their own line. justify-self: start, or
     a grid cell stretches a "+ Mark out" button to the full width of the
     column — a 470px target for a mouse pointer, which is the same complaint
     pointing the other way. */
  .attendance-person-row {
    grid-template-columns: minmax(8rem, 13rem) 1fr;
    column-gap: .75rem;
  }

  .attendance-person-row > *:not(.attendance-person-name),
  .attendance-person-row > .attendance-hour-chips {
    grid-column: 2;
    justify-self: start;
  }

  .attendance-group-label {
    margin-top: .5rem;
    margin-bottom: .1rem;
  }

  .attendance-family-out-btn {
    width: auto;
    font-size: .9rem;
    padding: .2rem .8rem;
    border-radius: .375rem;
  }

  .attendance-family-close-btn {
    width: auto;
    margin-left: auto;
    font-size: .9rem;
    padding: .2rem 1.2rem;
  }

  /* Twenty-four rooms in one 720px column is six screens of scrolling on a
     laptop. A room card's content is narrow — an hour, a title, a pair of
     counts and two to four names — so two columns fit without crowding and
     the tab becomes two and a half screens. align-items: start keeps each
     card its own height instead of stretching it to match its neighbour. */
  .attendance-room-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
  }
}

/* ---------------------------------------------------------------------------
 * Using the computer's screen.
 *
 * Samantha, 2026-09-07: "can you do a sweep of the website version to see if
 * we can optimize the screen for viewing. We are still stuck in trying to keep
 * mobile and site versions the same."
 *
 * Measured before this block, at 1920x1080: every other page in the app used
 * 98-99% of the width; the three attendance pages used 38%, because
 * .attendance-page is pinned to 720px so a phone lays out correctly. The fix
 * is not to stretch a row to 1900px — a name at one edge and its button at the
 * other is worse, not better — it is to let the lists become columns.
 * ------------------------------------------------------------------------- */
@media (min-width: 992px) {
  .attendance-page {
    max-width: 1400px;
  }

  .attendance-family-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(420px, 1fr));
    align-items: start;
  }

  /* The open family is the one card that needs width: a teaching parent's
     name, their "Teaches Hour 1, Hour 3" badge and four hour chips share a
     line. Two columns is roughly the 720px it was designed at. */
  .attendance-family-card:has(.attendance-family-detail) {
    grid-column: span 2;
  }

  .attendance-room-list {
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  }
}

/* Who has subbed, and when (attendance_stats.html). Phone-first like the rest
   of Merrilee's pages: one person per block, the dates wrapping under the
   name; from 768px up the three facts sit in columns. */
.attendance-subs {
  margin-top: 2rem;
}

.attendance-subs-note {
  font-size: .88rem;
  margin-bottom: .6rem;
}

.attendance-hour-filter {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-bottom: .6rem;
}

.attendance-hour-btn {
  min-height: 44px;
  padding: .3rem .9rem;
  border-radius: 999px;
  border: 1px solid var(--ub-line);
  background: var(--ub-surface);
  color: var(--ub-teal-ink);
  font-size: .88rem;
  font-weight: 600;
}

.attendance-hour-btn.is-current {
  background: var(--ub-teal-tint);
  border-color: var(--ub-teal-mid);
  color: var(--ub-teal-deep);
}

.attendance-sub-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--ub-line-soft);
}

.attendance-sub-row {
  display: grid;
  gap: .15rem;
  padding: .6rem .2rem;
  border-bottom: 1px solid var(--ub-line-soft);
}

.attendance-sub-name {
  font-weight: 600;
}

/* "it should note that so we know they weren't really free" — this parent is
   in the hour's list because she actually covered it, not because she was
   off that hour. */
.attendance-sub-pulled {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  background: var(--ub-amber-tint);
  color: var(--ub-amber-ink);
  border: 1px solid var(--ub-amber-line);
  border-radius: 999px;
  padding: .05rem .4rem;
  margin-left: .35rem;
  vertical-align: middle;
  white-space: nowrap;
}

.attendance-sub-when {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
}

.attendance-sub-date {
  font-size: .82rem;
  background: var(--ub-surface-2);
  border: 1px solid var(--ub-line-soft);
  border-radius: 999px;
  padding: .05rem .55rem;
  white-space: nowrap;
}

.attendance-sub-hour {
  color: var(--ub-slate);
  margin-left: .35rem;
}

.attendance-sub-never {
  font-size: .85rem;
  font-weight: 600;
  color: var(--ub-amber-ink);
}

.attendance-sub-free {
  font-size: .8rem;
  color: var(--ub-slate);
}

@media (min-width: 768px) {
  .attendance-sub-row {
    grid-template-columns: minmax(9rem, 15rem) minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: 1rem;
    padding: .35rem .2rem;
  }

  .attendance-hour-btn {
    min-height: 32px;
    padding: .15rem .8rem;
  }
}

/* A day still to come: say what this page is for before she starts tapping. */
.attendance-future-note {
  background: var(--ub-teal-tint);
  border-left: 4px solid var(--ub-teal-mid);
  color: var(--ub-teal-deep);
  border-radius: 0 .4rem .4rem 0;
  padding: .55rem .75rem;
  font-size: .9rem;
  margin-bottom: .75rem;
}

/* "the age group and the number of kids in the room" — the fact Merrilee
   reads the adult count against, so it sits with the room's name. */
.attendance-room-who {
  font-size: .8rem;
  color: var(--ub-slate-dark);
  margin-top: .3rem;
}

/* "22 kids" is one thing and must never be split across a line break, nor
   left behind by the age group in front of it. */
.attendance-room-kidcount,
.attendance-room-group {
  white-space: nowrap;
}

.attendance-room-dot {
  color: var(--ub-slate-400);
}

.attendance-room-kids-out {
  color: var(--ub-amber-ink);
  font-weight: 600;
}


/* ---------------------------------------------------------------------------
 * The schedule board's table skeleton.
 *
 * Lifted out of session_board.html's page <style> on 2026-09-07 so Merrilee's
 * attendance page can lay its rooms out the same way. Samantha: "let's change
 * this page to match the class planning page... I want this format." Two
 * copies of this would have drifted the first time either page was touched
 * (Ryan Standard §7), so there is one, here, and both pages use it. Everything
 * that is genuinely planning-only — drag and drop, the parent pool, the quick
 * edit modal — stayed on that page.
 * ------------------------------------------------------------------------- */
.schedule-board {
  width: 100%;
  table-layout: fixed;
}

/* Bootstrap's .5rem cell padding is ~18px of air per row; across a header,
   nine class groups and Off Hour that is a quarter of a 768px screen. This is
   the least that still reads, per Samantha's "optimizing the space and keeping
   the text as big as possible". */
.schedule-board th,
.schedule-board td {
  vertical-align: top;
  padding: .5rem .7rem;
  border-color: var(--ub-rule);
}

.schedule-board thead th {
  background: var(--ub-teal-deep);
  color: #fff;
  border-color: var(--ub-teal-deep);
}

.schedule-board thead th.group-cell {
  background: var(--ub-teal-deep);
  color: #fff;
}

.group-cell {
  width: 132px;
  background: var(--ub-surface-2);
  color: var(--ub-teal-ink);
}

.period-header-cell {
  text-align: center;
}

.group-child-count {
  font-size: .75rem;
  font-weight: 400;
  color: var(--ub-slate);
}

.cell-banner {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  padding: .1rem .3rem;
  margin-bottom: .15rem;
  border-radius: 3px;
  color: #0b5c69;
  background: #d5eef2;
}

/* "the shading of the electives is important" — each distinct range gets its
   own tint, so two separate choose-from sets never read as one list. Scoped
   through .schedule-board td to beat Bootstrap's `.table > :not(caption) > * >
   *`, which out-specifies a bare class and repaints every cell white. Teal,
   green and yellow all come from the logo, and none of them is the red or
   orange that mean something on the attendance side. */
.schedule-board td.drop-cell-tint-0 { background: var(--ub-teal-tint); box-shadow: inset 0 0 0 1px rgba(21, 188, 201, .30); }
.schedule-board td.drop-cell-tint-1 { background: var(--ub-green-tint); box-shadow: inset 0 0 0 1px rgba(31, 168, 115, .28); }
.schedule-board td.drop-cell-tint-2 { background: var(--ub-yellow-tint); box-shadow: inset 0 0 0 1px rgba(253, 175, 27, .30); }
.drop-cell-tint-0 .cell-banner { color: var(--ub-teal-ink); background: transparent; padding-left: 0; }
.drop-cell-tint-1 .cell-banner { color: var(--ub-green-ink); background: transparent; padding-left: 0; }
.drop-cell-tint-2 .cell-banner { color: var(--ub-amber-ink); background: transparent; padding-left: 0; }

.schedule-board td.drop-cell-combined {
  background: #f6f8f9;
}

/* ---------------------------------------------------------------------------
 * Merrilee's rooms, in the board's format.
 *
 * Samantha, 2026-09-07: "let's change this page to match the class planning
 * page. This seems messy and hard to follow." And, on the phone: "On a phone
 * you obviously cannot add the whole planning calendar like I previously
 * asked. So don't try to recreate it."
 *
 * So the board is the computer's view and the card list is the phone's. Both
 * draw from the same STATE, so they cannot disagree; CSS just picks which one
 * is on screen.
 * ------------------------------------------------------------------------- */
.attendance-board-wrap {
  display: none;
}

@media (min-width: 992px) {
  .attendance-board-wrap {
    display: block;
  }

  #room-list {
    display: none;
  }
}

.attendance-board .group-cell {
  font-weight: 600;
}

.attendance-board-room + .attendance-board-room {
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px dashed var(--ub-line);
}

.attendance-board-room-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
}

.attendance-board-room-title {
  font-weight: 700;
  color: var(--ub-teal-ink);
}

.attendance-board-count {
  font-variant-numeric: tabular-nums;
  color: var(--ub-slate);
  white-space: nowrap;
}

/* Red where the room is under its number, the same red the cards use. */
.attendance-board-count-short {
  color: var(--ub-red-deep);
  font-weight: 700;
}

.attendance-board-adults {
  font-size: .88rem;
  margin-top: .1rem;
}

.attendance-board-nobody {
  color: var(--ub-slate-400);
  font-style: italic;
}

.attendance-board-kids {
  font-size: .78rem;
  color: var(--ub-slate);
  margin-top: .15rem;
}

/* Her three levels, said the same way the cards say them: a red spine for a
   room under its number, orange for one waiting on her decision. Colour is
   never the only channel — the count turns red and bold as well. */
.attendance-board-room-short {
  border-left: 4px solid var(--ub-red);
  padding-left: .45rem;
  margin-left: -.15rem;
}

.attendance-board-room-undecided {
  border-left: 4px solid var(--ub-orange);
  padding-left: .45rem;
  margin-left: -.15rem;
}

.attendance-board-room-floor {
  background: var(--ub-red-wash);
}

.attendance-board-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  margin-top: .35rem;
}

.attendance-board-offhour .group-cell,
.attendance-board-offhour td {
  background: var(--ub-surface-2);
  font-size: .85rem;
}

.attendance-board-combined {
  font-size: .72rem;
  font-style: italic;
  color: var(--ub-slate);
  margin-top: .2rem;
}

/* The hour is short: say it on the dark header band without shouting, the
   same weight the planning board's own note carries. */
.period-note-short {
  color: #ffd3c9;
  background: rgba(217, 58, 30, .35);
}

/* The note on the header band. "Can we quiet the missing families alert?" —
   it was a bright warning badge on every hour, shouting a number she already
   knows and cannot act on from the header. It reads as a note on the dark
   band now, not an alarm. Shared with the attendance board, whose equivalent
   question is whether the hour is covered. */
.period-note {
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .01em;
  color: #b9ccd3;
  background: rgba(255, 255, 255, .10);
  border-radius: 999px;
  padding: .05rem .45rem;
  white-space: nowrap;
}

.period-note-ok {
  color: #a8d8bd;
}

.period-time {
  display: block;
  font-size: .72rem;
  font-weight: 400;
  color: #b9ccd3;
  letter-spacing: .01em;
}

/* Subs needed, day by day. "Shows whether it is getting better or worse", so
   it reads as a trend in date order, not a ranking. */
.attendance-daybyday {
  margin-top: 2rem;
}

.attendance-daybyday-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--ub-line-soft);
}

.attendance-daybyday-row {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) 4.5rem 4.5rem;
  align-items: center;
  column-gap: .6rem;
  padding: .35rem .2rem;
  border-bottom: 1px solid var(--ub-line-soft);
  font-size: .85rem;
}

.attendance-daybyday-date {
  font-weight: 600;
}

.attendance-daybyday-bar {
  display: block;
  height: .5rem;
  background: var(--ub-surface-2);
  border-radius: 999px;
  overflow: hidden;
}

.attendance-daybyday-bar > span {
  display: block;
  height: 100%;
  background: var(--ub-teal-mid);
  border-radius: 999px;
}

.attendance-daybyday-count {
  font-variant-numeric: tabular-nums;
}

.attendance-daybyday-kids {
  font-variant-numeric: tabular-nums;
  color: var(--ub-slate);
  text-align: right;
}

/* How many times this parent has subbed, in front of the dates that prove it. */
.attendance-sub-total {
  font-weight: 700;
  color: var(--ub-teal-ink);
  font-variant-numeric: tabular-nums;
  margin-right: .1rem;
}

/* The child's grade, beside their name in the open family panel — "a quick
   reminder where they belong". Quiet: it is a reminder, not a second name,
   and nine of them must not add up to a wall of text. */
.attendance-child-grade {
  font-size: .75rem;
  font-weight: 400;
  color: var(--ub-slate);
  white-space: nowrap;
  margin-left: .3rem;
}

/* "Added X to today's visitors" — said beside the button, because the list it
   lands in is above the form and off the part of the screen she is watching. */
.attendance-guest-added {
  margin-top: .5rem;
  margin-bottom: 0;
  color: var(--ub-green-ink);
  background: var(--ub-green-tint);
  border-radius: 6px;
  padding: .45rem .7rem;
  font-size: .9rem;
}

/* "There should be a checkbox for Merrilee to keep track of who she told
   already they are subbing in another room." Quiet until it is ticked, then
   plainly done — placing someone and telling them are two separate jobs and
   only the second one is in doubt. */
.attendance-told {
  border: 1px solid var(--ub-line);
  background: var(--ub-surface);
  color: var(--ub-slate-dark);
  border-radius: 999px;
  font-size: .75rem;
  padding: .05rem .5rem;
  min-height: 28px;
  white-space: nowrap;
}

.attendance-told-done {
  border-color: var(--ub-green-mid);
  background: var(--ub-green-tint);
  color: var(--ub-green-ink);
  font-weight: 600;
}

/* It is a link now, not a label, so it has to look like something to press. */
a.attendance-guest-pending {
  border: 1px solid var(--ub-amber-line);
  text-decoration: none;
  font-weight: 600;
  min-height: 32px;
  line-height: 1.9;
}

a.attendance-guest-pending:hover {
  background: var(--ub-yellow-tint);
  color: var(--ub-amber-ink);
}

/* "can we make the 'undo' smaller so it doesn't make every line become 2?"
   The word has to stay — a recorded chip that only carries a glyph reads as
   a label rather than something you can reverse — but it does not need to be
   the same size as the hour it belongs to. */
/* The hour chips are the one control she taps over and over, so their
   geometry must not change when tapped. Both states render the same three
   parts; only the mark and the visibility of "undo" differ, so the bubble is
   the same size before and after and nothing moves under her thumb. */
.attendance-hour-chips .attendance-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1.15;
  padding: .2rem .55rem;
}

/* A fixed box for the glyph, so "+" and the check mark do not size the
   bubble differently. */
.attendance-chip-mark {
  display: inline-block;
  width: .85em;
  text-align: center;
  margin-right: .15rem;
}

/* Taken out of the flow entirely, so the hour sits centred in the bubble
   whether or not there is an undo beneath it. Reserving the line instead
   pushed the hour upwards on every untapped chip, and next to a tapped one
   they read as misaligned — Samantha, 2026-09-08: "The hours by themselves
   look kinda funny, like they are misaligned without the undo under them."
   Absolute positioning keeps the promise that mattered: the bubble is the
   same size, and the hour does not move, when she taps it. */
.attendance-chip-undo {
  position: absolute;
  left: 0;
  right: 0;
  bottom: .15rem;
  font-size: .6rem;
  line-height: 1;
  opacity: .75;
}

.attendance-chip:not(.attendance-chip-absent) .attendance-chip-undo {
  display: none;
}

/* The once-a-semester jobs, below the list rather than above it. "They are
   very prominent for something that will rarely happen." */
.attendance-rare-actions {
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--ub-line-soft);
}


/* Every sub placed today, gathered where the coverage banner sends her, so
   telling eight people is eight taps in one place rather than a scroll
   through twenty-six rooms looking for the three that have one. */
/* Square on the left so the colour bar is a straight line, exactly as the
   room cards below it are. Samantha, 2026-09-08: "that text bubble has the
   curved edge instead of the straight one" — rounding all four corners bent
   the bar at top and bottom and it no longer matched the rooms. */
.attendance-subs-today:not(:empty) {
  background: var(--ub-surface);
  border: 1px solid var(--ub-line);
  border-left: 4px solid var(--ub-teal-mid);
  border-radius: 0 .4rem .4rem 0;
  padding: .6rem .75rem;
  margin-bottom: 1rem;
}

.attendance-subs-today-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .35rem;
}

.attendance-subs-today-title {
  font-weight: 700;
  color: var(--ub-teal-ink);
}

.attendance-subs-today-count {
  font-size: .82rem;
  color: var(--ub-amber-ink);
  font-weight: 600;
}

.attendance-subs-today-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.attendance-subs-today-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .3rem 0;
  border-top: 1px solid var(--ub-line-soft);
}

.attendance-subs-today-row:first-child {
  border-top: 0;
}

/* Told already: still listed, still reversible, just no longer the job. */
.attendance-subs-today-row.is-told .attendance-subs-today-who {
  color: var(--ub-slate);
}

.attendance-subs-today-who {
  display: flex;
  flex-direction: column;
  min-width: 0;
  font-weight: 600;
}

.attendance-subs-today-where {
  font-size: .78rem;
  font-weight: 400;
  color: var(--ub-slate);
}

/* One tap to the phone's messaging app. The number is in the href and never
   on the screen — "hiding it under the button Text will work great." */
/* Centred properly rather than positioned by line-height, which left the
   word sitting high in the pill. Samantha, 2026-09-08: "Can you center the
   text in the blue bubble." */
.attendance-text-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--ub-teal-mid);
  background: var(--ub-teal-tint);
  color: var(--ub-teal-deep);
  border-radius: 999px;
  font-size: .75rem;
  font-weight: 600;
  padding: .05rem .6rem;
  min-height: 28px;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  margin-right: .2rem;
}

.attendance-text-link:hover {
  background: var(--ub-teal-tint-deep);
  color: var(--ub-teal-deep);
}

.attendance-subs-today-actions {
  display: flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
}

/* The subs she has already spoken to, folded away. */
.attendance-subs-told-toggle {
  width: 100%;
  border: 0;
  background: none;
  text-align: left;
  padding: .4rem .1rem .1rem;
  color: var(--ub-slate);
  font-size: .85rem;
  min-height: 32px;
}

/* A day that ended with a room nobody could fill is the day that went badly. */
.attendance-daybyday-short {
  display: block;
  font-size: .74rem;
  color: var(--ub-red-deep);
  font-weight: 600;
}


/* ---------------------------------------------------------------------------
 * The family roster.
 *
 * Samantha, 2026-09-08: "I want to start with the family roster page. Let's
 * make this page more user friendly and nice to look at." Then, while it was
 * being built: "please keep in mind the overall look of the class planning
 * pages and how I want it to be. Same colors and feel."
 *
 * So this borrows the board's vocabulary rather than its widget: the teal-deep
 * band across the top, --ub-rule hairlines, the board's tight .5rem/.7rem
 * padding, and .cell-banner's small uppercase label for the badges. It is not a
 * table, because 30 families in 13 columns is eight families on a screen and
 * she needs "to be able to see everything at once" (HOUSE_STYLE §2) — a column
 * grid gets the whole co-op onto one laptop screen and one family onto one
 * phone line.
 *
 * No coloured spine down the side of a card: "I also would like to get rid of
 * the blue lines on the side of the classes" (§3).
 * ------------------------------------------------------------------------- */

.roster-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: .85rem;
}

.roster-head-actions {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}

/* Five 90px boxes, three of them reading zero, cost a fifth of the screen and
   pushed the families below the fold. Same five numbers, one line. */
.roster-stats {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem .95rem;
  align-items: baseline;
  padding: .5rem .7rem;
  margin-bottom: .85rem;
  background: var(--ub-surface-2);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
  color: var(--ub-teal-ink);
}

.roster-stat { font-size: .9rem; }
.roster-stat b { font-size: 1.05rem; font-weight: 700; }

/* Neutral at zero — §3, "a card is coloured by what it says". */
.roster-stat.is-zero { color: var(--ub-slate); }

.roster-tabs { margin-bottom: .85rem; }

/* Bootstrap's active tab is white-on-white with a hairline, which a cold
   reviewer read as disabled rather than current. The brand says which one it
   is: teal text, weight, and a teal edge along the top. */
.roster-tabs .nav-link {
  color: var(--ub-teal-link);
  border-radius: 0;
}

.roster-tabs .nav-link.active {
  color: var(--ub-teal-deep);
  font-weight: 700;
  border-top: 3px solid var(--ub-teal-mid);
}

/* The board's header band, carrying this page's controls. */
/* Samantha, 2026-09-08: "make sure all the bars on the top of bubbles are
   straight not curved." The same call she made on the Subs block's teal
   spine, and the schedule board she uses as the design reference is square
   throughout — so the band and the panel welded beneath it are one straight
   rectangle, not a rounded one. */
.roster-toolbar {
  display: flex;
  gap: .6rem 1.1rem;
  align-items: center;
  flex-wrap: wrap;
  padding: .55rem .7rem;
  background: var(--ub-teal-deep);
  border-radius: 0;
}

.roster-search { flex: 1 1 260px; margin: 0; }
.roster-search input { border-color: var(--ub-teal-deep); }

.roster-sort {
  display: flex;
  align-items: center;
  gap: .4rem;
}

.roster-sort label {
  color: #fff;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  white-space: nowrap;
}

.roster-sort select { width: auto; border-color: var(--ub-teal-deep); }

.roster-sort-dir {
  --bs-btn-color: #fff;
  --bs-btn-border-color: rgba(255, 255, 255, .55);
  --bs-btn-hover-bg: #fff;
  --bs-btn-hover-color: var(--ub-teal-deep);
  --bs-btn-hover-border-color: #fff;
  white-space: nowrap;
}

/* auto-fill, so the co-op gets wider as her screen does: one column on a
   phone, three at 1366, five on the 1858px screen she sent the screenshot
   from — thirty families, no scrolling. */
.roster-list {
  list-style: none;
  margin: 0;
  padding: .7rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: .5rem;
  background: var(--ub-surface-2);
  border: 1px solid var(--ub-rule);
  border-top: 0;
  border-radius: 0;
}

.roster-card {
  position: relative;
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
  padding: .5rem .7rem;
  /* room for the ••• menu so a long email never runs under it */
  padding-right: 2.4rem;
}

.roster-card-main {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .35rem .5rem;
}

/* The family is the point of the row, so it is the biggest thing on it —
   "uniformity is a defect" (§3). */
.roster-name {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--ub-teal-link);
  text-decoration: none;
}

.roster-name:hover { color: var(--ub-teal-deep); text-decoration: underline; }

/* The whole card answers to the pointer, so it reads as one thing you can
   open rather than a box with a link in it. */
.roster-card:hover {
  border-color: var(--ub-teal-mid);
  box-shadow: 0 1px 4px var(--ub-shadow);
}

.roster-card:hover .roster-name { text-decoration: underline; }

/* .group-child-count's treatment — the board says how many children a row has
   in exactly this voice. */
.roster-kids {
  margin-left: auto;
  font-size: .75rem;
  color: var(--ub-slate);
  text-decoration: none;
  white-space: nowrap;
}

.roster-kids:hover { color: var(--ub-teal-ink); text-decoration: underline; }

/* .cell-banner, reused: small, uppercase, letterspaced. Only ever drawn when
   there is something to say — never thirty pills all reading "Active". */
.roster-tag {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  padding: .1rem .3rem;
  border-radius: 3px;
  color: #0b5c69;
  background: #d5eef2;
  white-space: nowrap;
}

.roster-tag.is-waitlist   { color: var(--ub-amber-ink);  background: var(--ub-amber-tint); }
.roster-tag.is-prospective{ color: var(--ub-green-ink);  background: var(--ub-green-tint); }
.roster-tag.is-former,
.roster-tag.is-inactive   { color: var(--ub-slate-dark); background: var(--ub-line-soft); }

.roster-parents {
  font-size: .9rem;
  color: var(--ub-ink);
  margin-top: .1rem;
}

.roster-since {
  font-size: .75rem;
  color: var(--ub-slate);
  margin-left: .35rem;
}

.roster-contact {
  display: flex;
  flex-wrap: wrap;
  gap: .1rem .6rem;
  margin-top: .15rem;
  font-size: .8rem;
}

.roster-contact a { color: var(--ub-teal-link); text-decoration: none; }
.roster-contact a:hover { text-decoration: underline; }

/* Waitlist, Former and Delete are a few-times-a-year job. §3: rarely-used
   controls do not sit on every row. The trigger is quiet until the card is
   touched — but always present on a phone, where there is no hover. */
.roster-more { position: absolute; top: .3rem; right: .3rem; }

.roster-more > summary {
  list-style: none;
  cursor: pointer;
  width: 1.8rem;
  height: 1.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  color: var(--ub-slate-400);
  opacity: 0;
  transition: opacity .12s ease-in-out;
}

.roster-more > summary::-webkit-details-marker { display: none; }

.roster-card:hover .roster-more > summary,
.roster-more[open] > summary,
.roster-more > summary:focus-visible {
  opacity: 1;
}

.roster-more > summary:hover,
.roster-more[open] > summary {
  background: var(--ub-teal-tint);
  color: var(--ub-teal-ink);
}

.roster-more-menu {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 20;
  min-width: 12.5rem;
  display: flex;
  flex-direction: column;
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
  box-shadow: 0 6px 18px var(--ub-shadow);
  overflow: hidden;
}

.roster-more-menu a,
.roster-more-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: .5rem .7rem;
  font-size: .85rem;
  background: none;
  border: 0;
  color: var(--ub-ink);
  text-decoration: none;
}

.roster-more-menu form { margin: 0; }

.roster-more-menu a:hover,
.roster-more-menu button:hover { background: var(--ub-teal-tint); }

.roster-more-menu button.is-danger { color: var(--ub-red-deep); }
.roster-more-menu button.is-danger:hover { background: var(--ub-red-tint); }

.roster-empty,
.roster-count { padding: .5rem .2rem 0; font-size: .85rem; margin: 0; }

/* A phone gets its own answer, not a shrunken laptop (§2). One family per
   line, and the menu trigger is permanent and full-size because there is no
   hover and 44px is the floor. */
@media (max-width: 575.98px) {
  .roster-list { padding: .5rem; gap: .4rem; }
  .roster-card { padding-right: 3rem; }
  .roster-more { top: .1rem; right: .1rem; }
  .roster-more > summary { opacity: 1; width: 2.75rem; height: 2.75rem; }
  .roster-toolbar { border-radius: 0; }
  .roster-sort { width: 100%; }
  .roster-sort select { flex: 1; }
}

/* ---------------------------------------------------------------------------
 * Samantha 2026-09-09, Class Rosters on a phone.
 *
 * "Same issue here with visibility, you should be able to see this page well
 * on mobile and print if needed" — about the paper-shaped Class Rosters
 * printout, which shrinks to nothing at phone width. This is the on-screen
 * answer: a card per class group, name and age/grade on one flex row (no
 * table, so nothing scrolls sideways), stacked on a phone and a responsive
 * grid on a wider screen.
 * ------------------------------------------------------------------------- */
.roster-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: .75rem;
}
.roster-cards-card { padding: .7rem .85rem .8rem; }
.roster-cards-title {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
  margin-bottom: .4rem;
}
.roster-cards-count { font-size: .78rem; font-weight: 400; color: var(--ub-slate-dark); text-transform: none; letter-spacing: normal; }
.roster-cards-list { list-style: none; margin: 0; padding: 0; }
.roster-cards-list li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
  padding: .28rem 0;
  border-bottom: 1px solid var(--ub-line-soft);
  font-size: .95rem;
}
.roster-cards-list li:last-child { border-bottom: 0; }
.roster-cards-name { min-width: 0; overflow-wrap: break-word; }
.roster-cards-value { flex: none; font-weight: 700; color: var(--ub-teal-ink); }

@media (max-width: 575.98px) {
  .roster-cards-grid { grid-template-columns: 1fr; gap: .6rem; }
  .roster-cards-card { padding: .6rem .7rem .7rem; }
}


/* ---------------------------------------------------------------------------
 * One family, opened.
 *
 * Samantha, 2026-09-08: "next fix the screen of what you see when you open a
 * family." It reuses the roster's card, tag and menu classes rather than
 * copying them, so the two pages cannot drift (Ryan Standard §7); what is here
 * is only what a family page needs and the roster does not.
 * ------------------------------------------------------------------------- */

.family-page .roster-head { align-items: flex-start; }

.family-contact {
  display: flex;
  flex-wrap: wrap;
  gap: .1rem .9rem;
  font-size: .95rem;
}

.family-contact a { color: var(--ub-teal-link); text-decoration: none; }
.family-contact a:hover { text-decoration: underline; }

/* Facts, as many per row as fit, so a family with four of them does not leave
   three-quarters of a grid empty — and a fact with no value is never drawn at
   all, so there are no blank rows to read past. */
.family-facts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: .1rem .5rem;
  margin: 0 0 1rem;
  padding: .6rem .7rem;
  background: var(--ub-surface-2);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
}

.family-fact { margin: 0; padding: .18rem .2rem; }
.family-fact.is-wide { grid-column: 1 / -1; }

.family-fact dt {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-slate);
}

.family-fact dd {
  margin: 0;
  font-size: .92rem;
  color: var(--ub-ink);
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .35rem;
}

/* The board's small caps heading with a hairline under it — §3, "match the
   calendar page". */
.family-section { margin-bottom: 1.4rem; }

.family-section-title {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  padding-bottom: .3rem;
  margin-bottom: .6rem;
  border-bottom: 1px solid var(--ub-rule);
}

/* The count used to be a bare "8" in a grey pill beside the heading, saying
   nothing about what it counted (§4: numbers must say what they count). */
.family-section-count {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--ub-slate);
}

.family-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: center;
}

.family-actions form { margin: 0; }

.family-action-note {
  margin: .45rem 0 0;
  font-size: .85rem;
  color: var(--ub-slate);
}

/* The children and adults lists are roster grids that sit on the page rather
   than inside a toolbar, so they carry their own top edge. */
.family-children,
.family-adults {
  border-radius: 0;
  border-top: 1px solid var(--ub-rule);
}

/* A child's name is not a link — there is no page behind it — so it must not
   be painted like one. */
.roster-name.as-text { color: var(--ub-teal-ink); }
.roster-card:hover .roster-name.as-text { text-decoration: none; }

.family-child-nickname { font-weight: 400; color: var(--ub-slate-dark); }
.family-child-history { font-size: .78rem; }

/* Allergies were a narrow column, empty for almost every child. Amber, which
   in this app means "her decision, not an emergency", and never red: red is
   reserved for a room below its adult floor. It is a fact to carry, not an
   alarm to sound (§3, "do not shout"). */
.family-child-allergy {
  margin: .3rem 0 0;
  padding: .22rem .45rem;
  font-size: .82rem;
  color: var(--ub-amber-ink);
  background: var(--ub-amber-tint);
  border: 1px solid var(--ub-amber-line);
  border-radius: 3px;
}

.family-child-allergy span {
  text-transform: uppercase;
  letter-spacing: .07em;
  font-size: .68rem;
  font-weight: 700;
  margin-right: .3rem;
}

.family-allergy-summary {
  margin: -.2rem 0 .6rem;
  font-size: .85rem;
  color: var(--ub-amber-ink);
}

/* Add Student used to hold half the page open whether or not she was adding
   anyone. It is a disclosure now; the summary is the button. */
.family-add { margin-top: .7rem; }

.family-add > summary {
  display: inline-flex;
  list-style: none;
  cursor: pointer;
}

.family-add > summary::-webkit-details-marker { display: none; }

.family-add-form {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .6rem .8rem;
  margin-top: .7rem;
  padding: .8rem;
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
}

.family-add-form label {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  font-size: .8rem;
  font-weight: 600;
  color: var(--ub-slate-dark);
}

.family-add-form label.is-wide { grid-column: 1 / -1; }

.family-add-form label.is-check {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: .45rem;
  font-weight: 400;
}

.family-add-form .family-add-submit { grid-column: 1 / -1; }

.family-adult-edit {
  display: none;
  grid-column: 1 / -1;
  gap: .4rem;
  margin-top: .5rem;
  padding-top: .5rem;
  border-top: 1px solid var(--ub-rule);
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

/* Bootstrap's collapse toggles display, and the grid must survive it. */
.family-adult-edit.show { display: grid; }
.family-adult-edit .is-check {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .85rem;
}

@media (max-width: 575.98px) {
  .family-facts { grid-template-columns: 1fr; }
  .family-add-form { grid-template-columns: 1fr; }
}


/* ---------------------------------------------------------------------------
 * The calendar page.
 *
 * Samantha, 2026-09-08: "this all takes up way too much space. there is lots
 * of room to condense the information and make it easier to add", "I also
 * would like a calendar picker", "this color box is useless."
 *
 * The year is drawn as months, the way her printed sheet draws it, and days
 * are the control: click them, name them, done. Colour is decided by what a
 * day is, so there is nothing to pick.
 * ------------------------------------------------------------------------- */

.cal-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: .5rem;
  margin-bottom: .7rem;
}

.cal-head-actions { display: flex; gap: .4rem; flex-wrap: wrap; }
.cal-sub { margin: .1rem 0 0; font-size: .82rem; color: var(--ub-slate); }

/* The band, straight-cornered like every other bar in the app. It sticks so
   the day she clicks in December can still be named without scrolling back. */
.cal-toolbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--ub-teal-deep);
  padding: .5rem .7rem;
  border-radius: 0;
}

.cal-toolbar-main {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.cal-count {
  color: rgba(255, 255, 255, .75);
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  white-space: nowrap;
}

.cal-count.is-active { color: #fff; }

.cal-title { flex: 1 1 15rem; min-width: 0; }
.cal-type { flex: 0 0 auto; width: auto; }
.cal-title.is-missing { border-color: var(--ub-red); box-shadow: 0 0 0 .2rem var(--ub-red-tint); }

.cal-clear { color: rgba(255, 255, 255, .8); text-decoration: none; padding: 0 .3rem; }
.cal-clear:hover { color: #fff; text-decoration: underline; }

.cal-typed > summary {
  list-style: none;
  cursor: pointer;
  color: rgba(255, 255, 255, .8);
  font-size: .78rem;
  margin-top: .35rem;
}

.cal-typed > summary::-webkit-details-marker { display: none; }
.cal-typed > summary:hover { color: #fff; text-decoration: underline; }
.cal-typed-body { margin-top: .4rem; max-width: 34rem; }
.cal-hint { margin: .3rem 0 0; font-size: .75rem; color: rgba(255, 255, 255, .75); }
.cal-advanced-form .cal-hint { color: var(--ub-slate); }

/* As many months across as fit — her whole year on one screen on a laptop,
   two columns on a phone, rather than an 1840px column of forms. */
.cal-year {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: .6rem;
  padding: .7rem;
  background: var(--ub-surface-2);
  border: 1px solid var(--ub-rule);
  border-top: 0;
}

.cal-month {
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
  padding: .4rem .45rem .5rem;
}

.cal-month-title {
  font-size: .8rem;
  font-weight: 700;
  color: var(--ub-teal-ink);
  text-align: center;
  margin: 0 0 .25rem;
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
}

.cal-dow {
  font-size: .62rem;
  font-weight: 700;
  color: var(--ub-slate);
  text-align: center;
  padding-bottom: .1rem;
}

.cal-day {
  font-size: .72rem;
  line-height: 1;
  text-align: center;
  padding: .32rem 0;
  border: 1px solid transparent;
  border-radius: 3px;
  background: none;
  color: var(--ub-ink);
  cursor: pointer;
}

.cal-day.is-outside { color: var(--ub-slate-400); cursor: default; opacity: .55; }
.cal-day:hover:not(.is-outside) { background: var(--ub-teal-tint); }

/* A day already carrying an event wears that event's colour, faintly, the way
   the printed sheet shades it. */
.cal-day[style*="--day-color"] {
  background: color-mix(in srgb, var(--day-color) 18%, white);
  border-color: color-mix(in srgb, var(--day-color) 35%, white);
  font-weight: 600;
}

/* A day picked right now wears the colour it is about to become, filled — so
   the choice is visible before anything is saved.
   
   The :hover variant is not decoration: `.cal-day:hover:not(.is-outside)` is
   three specificity points against `.cal-day.is-picked`'s two, so hover won
   and the day *under the cursor* — the one just clicked — went pale teal with
   white text on it. Invisible, every single time, on the day she was looking
   at. HOUSE_STYLE §9: look at the rendered box, not the stylesheet. Caught by
   reading computed backgrounds off the four picked days, three red and one
   #e4f6f8. */
.cal-day.is-picked,
.cal-day.is-picked:hover {
  background: var(--pick-color, var(--ub-teal-deep));
  border-color: var(--pick-color, var(--ub-teal-deep));
  color: #fff;
  font-weight: 700;
}

.cal-legend {
  list-style: none;
  margin: .35rem 0 0;
  padding: 0;
  font-size: .68rem;
  color: var(--ub-slate-dark);
}

.cal-legend li { display: flex; align-items: center; gap: .25rem; margin-top: .1rem; }

.cal-swatch {
  width: .6rem;
  height: .6rem;
  border-radius: 2px;
  flex: 0 0 auto;
}

.cal-section-title {
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  padding-bottom: .3rem;
  margin: 1.2rem 0 .5rem;
  border-bottom: 1px solid var(--ub-rule);
}

/* One line per event. It was a table of ten columns. */
.cal-list { list-style: none; margin: 0; padding: 0; }

/* A grid, not a flex row. Samantha, 2026-09-08: "Push the names of the items
   over so they are left justified at the same spot, not indented funny
   because the date was long." A repeating event's date reads "Sep 11 – Apr 09
   · weekly", which is three times the width of "Oct 16", and with flex that
   one row's title started further right than every other. Fixed columns mean
   every title begins at the same x whatever the date says. */
.cal-list-row {
  display: grid;
  grid-template-columns: .8rem 11rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: .1rem .6rem;
  padding: .3rem .2rem;
  border-bottom: 1px solid var(--ub-line-soft);
  font-size: .85rem;
}

.cal-list-when { color: var(--ub-slate-dark); }
.cal-list-title { font-weight: 600; }
/* Title and its details share the third column, so the details sit against
   the title rather than at three unpredictable tab stops. */
.cal-list-title { grid-column: 3; }

.cal-list-details {
  grid-column: 3;
  display: flex;
  flex-wrap: wrap;
  gap: .1rem .5rem;
}

.cal-list-type,
.cal-list-time { font-size: .75rem; color: var(--ub-slate); }
.cal-list-actions { display: flex; gap: .5rem; align-items: baseline; }
.cal-list-actions form { margin: 0; }

.cal-list-actions a,
.cal-list-actions button {
  font-size: .78rem;
  background: none;
  border: 0;
  padding: 0;
  color: var(--ub-teal-link);
  text-decoration: none;
}

.cal-list-actions button { color: var(--ub-red-deep); }
.cal-list-actions a:hover, .cal-list-actions button:hover { text-decoration: underline; }

.cal-advanced { margin-top: 1.2rem; }
.cal-advanced > summary { display: inline-flex; list-style: none; cursor: pointer; }
.cal-advanced > summary::-webkit-details-marker { display: none; }

.cal-advanced-form {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: .5rem .7rem;
  margin-top: .6rem;
  padding: .7rem;
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
}

.cal-advanced-form label {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  font-size: .75rem;
  font-weight: 600;
  color: var(--ub-slate-dark);
}

.cal-advanced-form .is-wide { grid-column: 1 / -1; }
.cal-danger { margin-top: 1.5rem; }

@media (max-width: 575.98px) {
  .cal-year { grid-template-columns: repeat(2, 1fr); padding: .5rem; }
  .cal-toolbar { position: static; }
  .cal-day { padding: .45rem 0; }
}

/* Samantha, 2026-09-08: "maybe we just need to include all months and maybe I
   can exclude them from my view if I want?" Twelve months are always drawn;
   this hides the ones with nothing on them, and it is her choice, not the
   app's. */
.cal-hide-standalone { display: block; margin: 0 0 0.75rem; }
.cal-hide {
  color: rgba(255, 255, 255, .85);
  font-size: .78rem;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  margin-top: .35rem;
  margin-right: 1rem;
  cursor: pointer;
}

.cal-hide:hover { color: #fff; }
.cal-year.is-hiding-empty .cal-month.is-empty { display: none; }

/* Samantha, 2026-09-08: "the edit event on mobile should be more compact."
   The add-forms' grid, used standalone. On a phone it pairs the fields that
   belong together — the two dates, the two times — rather than giving each a
   full-width row, which is what made one meeting six screens of scrolling. */
.cal-advanced-form.is-standalone { margin-top: 0; }
.cal-form-actions { display: flex; gap: .5rem; }

@media (max-width: 575.98px) {
  .cal-advanced-form { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .45rem .5rem; }
  .cal-advanced-form label { font-size: .72rem; }
}

/* Announcement history. One row per announcement, every meeting it was read at
   listed — the homepage shows only today's, so this is the only place the rest
   of the record exists. */
.announce-history { list-style: none; margin: 0; padding: 0; }

.announce-history-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: .2rem .8rem;
  padding: .55rem .2rem;
  border-bottom: 1px solid var(--ub-line-soft);
}

.announce-history-text { font-size: .95rem; color: var(--ub-ink); }
.announce-history-row.is-archived .announce-history-text { color: var(--ub-slate-dark); }

.announce-history-meta {
  grid-column: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3rem .6rem;
  font-size: .78rem;
}

.announce-history-dates { color: var(--ub-slate); }
.announce-history-actions { grid-row: 1 / span 2; grid-column: 2; align-self: center; }
.announce-history-actions form { margin: 0; }


/* ---------------------------------------------------------------------------
 * The electives board.
 *
 * Samantha, 2026-09-08: "I need the electives part built, that is where there
 * are missing students." Laid out like the spreadsheet she works in: a block
 * per grade band, split into two rotations, a column per elective, a total
 * under every column.
 * ------------------------------------------------------------------------- */

.electives-block { margin-bottom: 1.4rem; }

.electives-block-title {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  font-size: .85rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  padding-bottom: .3rem;
  margin-bottom: .6rem;
  border-bottom: 1px solid var(--ub-rule);
}

.electives-block-hour {
  text-transform: none;
  letter-spacing: 0;
  color: #fff;
  background: var(--ub-teal-deep);
  padding: .1rem .4rem;
  border-radius: 3px;
  font-size: .7rem;
}

.electives-block-count {
  margin-left: auto;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--ub-slate);
}

.electives-adopt {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin-bottom: .7rem;
  padding: .45rem .6rem;
  font-size: .82rem;
  color: var(--ub-amber-ink);
  background: var(--ub-amber-tint);
  border: 1px solid var(--ub-amber-line);
  border-radius: 4px;
}

/* The two rotations side by side, as on her sheet. */
.electives-rotations {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: .8rem;
}

.electives-rotation-title {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-slate-dark);
  margin: 0 0 .35rem;
}

.electives-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: .4rem;
  align-items: start;
}

.electives-column {
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  min-height: 6rem;
}

/* The working list, not a leftovers bin: the block is finished when it is
   empty, so it reads as a job rather than as spare parts. */
.electives-column.is-unplaced { background: var(--ub-surface-2); }

.electives-column.is-over {
  border-color: var(--ub-green-mid);
  background: var(--ub-green-tint);
}

.electives-column-head {
  font-size: .78rem;
  font-weight: 700;
  color: var(--ub-teal-ink);
  padding: .3rem .45rem;
  border-bottom: 1px solid var(--ub-rule);
}

/* An empty block starts with every child in one column, which was a 38-name
   wall next to three empty boxes — the columns she is aiming at were the
   smallest thing on screen. The list scrolls inside its own column instead, so
   the page stays a working surface rather than a list. */
.electives-list {
  list-style: none;
  margin: 0;
  padding: .25rem;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: .15rem;
  max-height: 15rem;
  overflow-y: auto;
  min-height: 3.5rem;
}

.electives-child {
  font-size: .78rem;
  line-height: 1.25;
  padding: .18rem .35rem;
  border-radius: 3px;
  background: var(--ub-teal-tint);
  color: var(--ub-ink);
  cursor: grab;
}

.electives-child:hover { background: var(--ub-teal-tint-deep); }
.electives-child.is-dragging { opacity: .45; }
.electives-child-family { color: var(--ub-slate); }

/* Her sheet totals every column, and she re-adjusts until the numbers work. */
.electives-total {
  font-size: .72rem;
  font-weight: 700;
  color: var(--ub-slate-dark);
  text-align: center;
  padding: .25rem;
  border-top: 1px solid var(--ub-rule);
  background: var(--ub-surface-2);
}

.electives-total.is-done { color: var(--ub-green-ink); }

@media (max-width: 767.98px) {
  .electives-columns { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}




/* ---------------------------------------------------------------------------
 * The homepage.
 *
 * Samantha, 2026-09-08: "Keep it compact, tidy, and information-dense... No
 * decorative hero sections, welcome banners, quotes, or filler content. Avoid
 * large tiles when a compact row/button will work. No large Dashboard
 * heading."
 * ------------------------------------------------------------------------- */

.home-date {
  font-size: .85rem;
  color: var(--ub-slate-dark);
  margin: 0 0 .7rem;
}

.home-section-title {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  padding-bottom: .25rem;
  margin: 0 0 .5rem;
  border-bottom: 1px solid var(--ub-rule);
}

.home-section-link {
  margin-left: auto;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  font-size: .75rem;
}

/* Only drawn when there is something wrong, so it can afford to be noticed. */
.home-attention {
  margin-bottom: 1rem;
  padding: .5rem .7rem;
  background: var(--ub-amber-tint);
  border: 1px solid var(--ub-amber-line);
  border-radius: 4px;
}

.home-attention .home-section-title {
  color: var(--ub-amber-ink);
  border-bottom-color: var(--ub-amber-line);
}

.home-attention-list { list-style: none; margin: 0; padding: 0; font-size: .85rem; }

.home-attention-list li {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  padding: .15rem 0;
}

.home-attention-list a { margin-left: auto; white-space: nowrap; }

/* "Larger left column: Current Announcements. Narrower right column: Quick
   Links first, Upcoming Dates below it." */
.home-columns {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(240px, 1fr);
  gap: 1rem;
  align-items: start;
}

.home-side { display: flex; flex-direction: column; gap: 1rem; }

/* "This should be the most prominent open box on the homepage." */
.home-announce-list { list-style: none; margin: 0; padding: 0; }

.home-announce {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: .5rem;
  padding: .4rem .2rem;
  border-bottom: 1px solid var(--ub-line-soft);
}

.home-announce.is-dragging { opacity: .45; }

.home-announce-grip {
  color: var(--ub-slate-400);
  cursor: grab;
  font-size: .8rem;
  line-height: 1.5;
}

/* Read aloud from here, so the words are the biggest thing on the row. */
.home-announce-text {
  font-size: .98rem;
  line-height: 1.35;
  color: var(--ub-ink);
  padding: .1rem .25rem;
  border-radius: 3px;
  border: 1px solid transparent;
}

.home-announce-text:hover { border-color: var(--ub-line); }

.home-announce-text:focus {
  outline: none;
  border-color: var(--ub-teal-mid);
  background: var(--ub-surface);
}

.home-announce.is-announced .home-announce-text { color: var(--ub-slate-dark); }

.home-announce-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  white-space: nowrap;
}

.home-announce-actions form { margin: 0; }

.home-announce-mark,
.home-announce-archive {
  background: none;
  border: 0;
  padding: 0;
  font-size: .75rem;
  color: var(--ub-teal-link);
}

.home-announce-mark:hover:not(:disabled),
.home-announce-archive:hover { text-decoration: underline; color: var(--ub-teal-deep); }
.home-announce-mark:disabled { color: var(--ub-slate-400); }
.home-announce.is-announced .home-announce-mark { color: var(--ub-green-ink); font-weight: 700; }

.home-add { margin-top: .5rem; }
.home-add > summary { list-style: none; cursor: pointer; font-size: .85rem; color: var(--ub-teal-link); }
.home-add > summary::-webkit-details-marker { display: none; }
.home-add > summary:hover { text-decoration: underline; }
.home-add-form { display: flex; gap: .4rem; margin-top: .45rem; }

/* "Use two compact columns... small rectangular rows/buttons rather than large
   icon tiles." */
.home-link-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .3rem;
}

.home-link-grid a {
  display: block;
  padding: .35rem .5rem;
  font-size: .8rem;
  text-decoration: none;
  color: var(--ub-teal-ink);
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 3px;
}

.home-link-grid a:hover { background: var(--ub-teal-tint); border-color: var(--ub-teal-mid); }

.home-links-note {
  margin: .4rem 0 0;
  font-size: .72rem;
  color: var(--ub-slate);
}

.home-date-list { list-style: none; margin: 0; padding: 0; }

.home-date-list a {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  padding: .25rem .2rem;
  font-size: .85rem;
  text-decoration: none;
  color: var(--ub-ink);
  border-bottom: 1px solid var(--ub-line-soft);
}

.home-date-list a:hover { background: var(--ub-teal-tint); }
.home-date-when { color: var(--ub-teal-ink); font-weight: 600; }

/* "The schedule needs the horizontal width, so do not squeeze it into the left
   column." Full width, below both. */
.home-schedule { margin-top: 1.1rem; }

.home-schedule-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: .5rem;
  text-decoration: none;
}

.home-schedule-hour {
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 4px;
  padding: .4rem .5rem;
}

.home-schedule-grid:hover .home-schedule-hour { border-color: var(--ub-teal-mid); }

.home-schedule-hour-name {
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  margin-bottom: .2rem;
}

.home-schedule-hour ul { list-style: none; margin: 0; padding: 0; }

.home-schedule-hour li {
  font-size: .8rem;
  color: var(--ub-ink);
  padding: .04rem 0;
}

.home-empty { font-size: .85rem; margin: .3rem 0 0; }

@media (max-width: 767.98px) {
  .home-columns { grid-template-columns: 1fr; }
  .home-announce { grid-template-columns: auto minmax(0, 1fr); }
  .home-announce-actions { grid-column: 2; }
}


/* ---------------------------------------------------------------------------
 * Homepage, second pass. Samantha, 2026-09-08 evening: "I do want dashboard to
 * look nice as well, right now it's just a basic page with zero appeal."
 *
 * She asked for compact and got bare. The board and the calendar carry the
 * co-op's visual language — the deep-teal band, tinted blocks, straight
 * corners — and the first homepage had none of it: grey captions over
 * hairlines. Same content, same density, same rules (no hero, no greeting, no
 * filler); it just wears the same clothes as the rest of the app now.
 *
 * Appended after the first pass so these rules win the cascade.
 * ------------------------------------------------------------------------- */

.home-card {
  background: var(--ub-surface);
  border: 1px solid var(--ub-rule);
  border-radius: 0;
  padding: 0 0 .5rem;
}

/* The board's header band, as every section's title. */
.home-card > .home-section-title {
  background: var(--ub-teal-deep);
  color: #fff;
  border-bottom: 0;
  padding: .42rem .7rem;
  margin: 0 0 .5rem;
  font-size: .74rem;
}

.home-card > .home-section-title .home-section-link {
  color: rgba(255, 255, 255, .85);
  text-decoration: none;
}

.home-card > .home-section-title .home-section-link:hover {
  color: #fff;
  text-decoration: underline;
}

/* Body content sits inside the card with the board's own padding. */
.home-announce-list,
.home-add,
.home-link-grid,
.home-date-list,
.home-empty,
.home-attention-list {
  margin-left: .7rem;
  margin-right: .7rem;
}

.home-columns { gap: .9rem; }
.home-side { gap: .9rem; }

/* Needs attention: an amber band, so it is unmistakably a different kind of
   box from the four teal ones, and only ever present when something is wrong. */
.home-attention.home-card {
  background: var(--ub-amber-tint);
  border-color: var(--ub-amber-line);
  margin-bottom: .9rem;
}

.home-attention.home-card > .home-section-title {
  background: var(--ub-amber-ink);
  color: #fff;
  border-bottom-color: transparent;
}

.home-attention-list a { color: var(--ub-amber-ink); font-weight: 600; }

/* Announcements are the point of the page. The words are big enough to read
   aloud across a room, each on its own tinted row, the newest first. */
.home-announce {
  padding: .5rem .45rem;
  border-bottom: 1px solid var(--ub-line-soft);
}

.home-announce:nth-child(odd) { background: var(--ub-surface-3); }

.home-announce-text { font-size: 1.05rem; line-height: 1.4; }

.home-announce.is-announced { background: var(--ub-green-tint); }

.home-announce-mark,
.home-announce-archive { font-size: .78rem; }

.home-add > summary {
  display: inline-block;
  padding: .3rem .6rem;
  color: var(--ub-teal-ink);
  background: var(--ub-teal-tint);
  border: 1px solid var(--ub-teal-tint-deep);
  border-radius: 0;
  font-weight: 600;
}

.home-add > summary:hover { background: var(--ub-teal-tint-deep); text-decoration: none; }

/* Quick links: filled, tinted, square — they read as things you press. */
.home-link-grid a {
  padding: .45rem .55rem;
  font-weight: 600;
  color: var(--ub-teal-ink);
  background: var(--ub-teal-tint);
  border: 1px solid var(--ub-teal-tint-deep);
  border-radius: 0;
}

.home-link-grid a:hover {
  background: var(--ub-teal-deep);
  border-color: var(--ub-teal-deep);
  color: #fff;
}

.home-date-list a { padding: .32rem .3rem; }
.home-date-list li:first-child a { background: var(--ub-yellow-tint); }  /* the next one, like "today" on the board */

/* Schedule preview: each hour under its own band, exactly the board's thead. */
.home-schedule.home-card { padding: .5rem .7rem .7rem; }

.home-schedule.home-card > .home-section-title { margin: -.5rem -.7rem .6rem; }

.home-schedule-grid { gap: .6rem; }

.home-schedule-hour {
  padding: 0 0 .35rem;
  border-radius: 0;
  border-color: var(--ub-rule);
}

.home-schedule-hour-name {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  background: var(--ub-surface-2);
  color: var(--ub-teal-ink);
  padding: .3rem .5rem;
  margin-bottom: .3rem;
  border-bottom: 2px solid var(--ub-teal-deep);
}

.home-schedule-hour-name span {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  color: var(--ub-slate);
}

.home-schedule-hour li { padding: .1rem .5rem; }
.home-schedule-hour li:nth-child(even) { background: var(--ub-surface-3); }

/* Samantha, 2026-09-08: "it would be nice to have some filters here so I can
   find names easier." One per block, narrowing every column at once. */
.electives-filter {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .6rem;
  max-width: 24rem;
}

.electives-filter-count { font-size: .75rem; color: var(--ub-slate); white-space: nowrap; }
.electives-child[hidden] { display: none; }

/* ---------------------------------------------------------------------------
 * Homepage, third pass — her mockup. Samantha, 2026-09-08 22:15, with a picture
 * of the page she wants: "use this as a guide for the home page. I like the
 * blue background that fades. Pick a more subtle alert color other than the
 * red though."
 *
 * What the picture says: a pale blue ground fading to white (set page-side in
 * dashboard.html), white cards with rounded corners and a soft shadow, an icon
 * beside each section title, quick links as icon rows, dates as a list with a
 * chevron, the schedule hours under pale blue bands. Same content, same layout,
 * same density rules as the first pass. Appended so it wins the cascade over
 * the second pass; the straight-cornered look stays on the board and calendar.
 * ------------------------------------------------------------------------- */

.home-fresh .home-date { font-size: 1rem; color: var(--ub-teal-deep); margin-bottom: .8rem; }

.home-fresh .home-card {
  background: var(--ub-surface);
  border: 1px solid rgba(11, 74, 80, .10);
  border-radius: 12px;
  box-shadow: 0 4px 14px rgba(20, 34, 35, .06);
  padding: .85rem 1rem 1rem;
}

.home-fresh .home-card > .home-section-title {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: transparent;
  color: var(--ub-teal-deep);
  font-size: 1rem;
  text-transform: none;
  letter-spacing: 0;
  padding: 0 0 .55rem;
  margin: 0 0 .7rem;
  border-bottom: 1px solid var(--ub-teal-tint-deep);
}
.home-fresh .home-title-icon { color: var(--ub-teal-ink); font-size: 1.15rem; }
.home-fresh .home-card > .home-section-title .home-section-link {
  color: var(--ub-teal-link);
  font-size: .78rem;
  font-weight: 600;
}
.home-fresh .home-card > .home-section-title .home-section-link:hover { color: var(--ub-teal-deep); }

.home-fresh .home-announce-list,
.home-fresh .home-add,
.home-fresh .home-link-grid,
.home-fresh .home-date-list,
.home-fresh .home-empty,
.home-fresh .home-attention-list { margin-left: 0; margin-right: 0; }

/* Needs attention: warm and quiet, not red — her call. Only present when
   something is wrong. */
.home-fresh .home-attention.home-card {
  background: #FFF8E6;
  border-color: #F2DCA2;
  margin-bottom: 1rem;
}
.home-fresh .home-attention.home-card > .home-section-title {
  color: var(--ub-amber-ink);
  border-bottom: 0;
  padding-bottom: .2rem;
  margin-bottom: .3rem;
}
.home-fresh .home-attention .home-title-icon { color: var(--ub-orange); }
.home-fresh .home-attention-list { font-size: .95rem; color: var(--ub-ink); }
.home-fresh .home-attention-list li { align-items: center; gap: 1rem; padding: .2rem 0; }
.home-fresh .home-attention-action {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .45rem .8rem;
  border-radius: 8px;
  background: var(--ub-teal-deep);
  color: #fff;
  font-weight: 600;
  font-size: .85rem;
  text-decoration: none;
}
.home-fresh .home-attention-action:hover { background: var(--ub-teal-ink); color: #fff; }

/* Announcements. */
.home-fresh .home-announce { border-radius: 8px; border-bottom: 0; margin-bottom: .25rem; }
.home-fresh .home-announce:nth-child(odd) { background: #F3FAFB; }
.home-fresh .home-empty-state { text-align: center; padding: 1.6rem 1rem 1.2rem; }
.home-fresh .home-empty-state .bi { font-size: 4.5rem; color: #C9D6DA; display: block; line-height: 1; margin-bottom: .6rem; }
.home-fresh .home-empty-title { font-weight: 700; font-size: 1.05rem; color: var(--ub-ink); margin: 0 0 .25rem; }
.home-fresh .home-empty-hint { font-size: .88rem; color: var(--ub-slate); margin: 0 auto; max-width: 22rem; }
.home-fresh .home-add { margin-top: .6rem; }
.home-fresh .home-add > summary {
  display: block;
  text-align: center;
  padding: .65rem;
  border-radius: 8px;
  background: var(--ub-teal-tint);
  border: 1px solid var(--ub-teal-tint-deep);
  color: var(--ub-teal-ink);
  font-weight: 600;
}
.home-fresh .home-add > summary:hover { background: var(--ub-teal-tint-deep); }
.home-fresh .home-add-form .form-control { border-radius: 8px; }
.home-fresh .home-add-form .btn { border-radius: 8px; }

/* Quick links: icon rows, two columns, pale blue. */
.home-fresh .home-link-grid { gap: .45rem; }
.home-fresh .home-link-grid a {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .7rem .75rem;
  border-radius: 8px;
  background: #EEF7FA;
  border: 1px solid transparent;
  color: var(--ub-teal-deep);
  font-weight: 500;
  font-size: .85rem;
}
.home-fresh .home-link-grid a .bi { color: var(--ub-teal-ink); font-size: 1.05rem; }
.home-fresh .home-link-grid a:hover { background: var(--ub-teal-tint-deep); border-color: var(--ub-teal-mid); color: var(--ub-teal-deep); }

/* Upcoming dates: a list with a chevron, the next one no longer highlighted
   because the list is short enough to read whole. */
.home-fresh .home-date-list a {
  align-items: center;
  padding: .55rem .3rem;
  font-size: .95rem;
  font-weight: 500;
  color: var(--ub-ink);
  border-bottom: 1px solid var(--ub-line-soft);
}
.home-fresh .home-date-list li:last-child a { border-bottom: 0; }
.home-fresh .home-date-list li:first-child a { background: transparent; }
.home-fresh .home-date-when { color: var(--ub-ink); font-weight: 500; }
.home-fresh .home-chevron { margin-left: auto; color: var(--ub-teal-link); font-size: .8rem; }
.home-fresh .home-date-list a:hover { background: #F3FAFB; }

/* Schedule preview: each hour under a pale blue band, rounded. */
.home-fresh .home-schedule.home-card { padding: .85rem 1rem 1rem; }
.home-fresh .home-schedule.home-card > .home-section-title { margin: 0 0 .7rem; }
.home-fresh .home-schedule-hour {
  border-radius: 8px;
  border: 1px solid var(--ub-teal-tint-deep);
  overflow: hidden;
  padding-bottom: .3rem;
}
.home-fresh .home-schedule-grid:hover .home-schedule-hour { border-color: var(--ub-teal-mid); }
.home-fresh .home-schedule-hour-name {
  background: var(--ub-teal-tint);
  color: var(--ub-teal-deep);
  border-bottom: 0;
  text-transform: none;
  letter-spacing: 0;
  font-size: .9rem;
  padding: .45rem .6rem;
}
.home-fresh .home-schedule-hour-name span { font-size: .78rem; }
.home-fresh .home-schedule-hour li { font-size: .85rem; padding: .18rem .6rem; }
.home-fresh .home-schedule-hour li:nth-child(even) { background: #F3FAFB; }

.home-fresh .home-columns { gap: 1rem; }
.home-fresh .home-side { gap: 1rem; }

/* ---------------------------------------------------------------------------
 * Shared page furniture, from the homepage look she chose (2026-09-08 22:15):
 * white cards with soft corners and a soft shadow, an icon beside each title,
 * plain tabs. First used on the semester page — "It needs to be updated to
 * look like everything else we have done. I want tabs instead of an endless
 * scroll like it is now." (22:17)
 * ------------------------------------------------------------------------- */
.page-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: .5rem .75rem;
  margin-bottom: .75rem;
}
.page-head h1 { color: var(--ub-teal-deep); }
.page-head-sub { font-size: .9rem; font-weight: 400; color: var(--ub-slate-dark); margin-left: .35rem; }

.ub-card {
  background: var(--ub-surface);
  border: 1px solid rgba(11, 74, 80, .10);
  border-radius: 12px;
  box-shadow: 0 4px 14px rgba(20, 34, 35, .06);
  padding: .85rem 1rem 1rem;
  margin-bottom: 1rem;
}
.ub-card-title {
  display: flex;
  align-items: center;
  gap: .5rem;
  color: var(--ub-teal-deep);
  font-size: 1rem;
  font-weight: 700;
  padding: 0 0 .55rem;
  margin: 0 0 .75rem;
  border-bottom: 1px solid var(--ub-teal-tint-deep);
}
.ub-card-title .bi { color: var(--ub-teal-ink); font-size: 1.1rem; }
.ub-card-title-end { margin-left: auto; font-size: .9rem; font-weight: 600; color: var(--ub-ink); }

.ub-tabs { margin-bottom: 1rem; }
.ub-tabs .nav-link { font-weight: 600; color: var(--ub-teal-link); padding: .5rem 1rem; }
.ub-tabs .nav-link.active { color: var(--ub-teal-deep); }

/* Tables inside cards: no grid lines. Samantha, 2026-09-08 22:25: "I'm trying to
   make the page more inviting, not just a stale spreadsheet." Hairline rows, a
   quiet teal header, a tint on hover — the data, without the cage. */
.ub-table { --bs-table-bg: transparent; border-color: var(--ub-line-soft); }
.ub-table > thead > tr > th {
  border-bottom: 2px solid var(--ub-teal-tint-deep);
  color: var(--ub-teal-ink);
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  background: transparent;
}
.ub-table > tbody > tr > td { border-bottom: 1px solid var(--ub-line-soft); border-top: 0; }
.ub-table > tbody > tr:last-child > td { border-bottom: 0; }
.ub-table > tbody > tr:hover > td { background: #F3FAFB; }
.ub-table a { font-weight: 600; text-decoration: none; }
.ub-table a:hover { text-decoration: underline; }

/* The top bar: teal, with the logo. Her homepage picture (2026-09-08 22:15) has
   it on every page, and with the dark grey bar left in place she said the result
   "is not it." */
.ub-navbar {
  background: linear-gradient(90deg, #0B4A50 0%, #0E7A83 60%, #12A4AF 100%);
  padding-top: .5rem;
  padding-bottom: .5rem;
}
.ub-brand { padding: 0; }
/* "slightly bigger, not much at all just to give the logo more breathing room"
   (Samantha, 2026-09-08 22:51). */
.ub-brand-logo { height: 54px; width: auto; display: block; margin: .15rem 0; }

/* ---------------------------------------------------------------------------
 * Homepage, fourth pass. Samantha, 2026-09-08 22:33: "the biggest problem is
 * the wasted space... it needs more color than just the blue... I don't like
 * how the classes span the entire bottom of the screen (only talking about the
 * website here, not mobile)... I like the teal color that fades."
 *
 * Two columns on a laptop, the schedule under the announcements; each card
 * carries one logo colour as a top edge and title icon (--accent); the hours
 * take the board's three tints; dates carry their type colour.
 * ------------------------------------------------------------------------- */
.home-fresh .home-columns {
  grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
  grid-template-areas: "announce side" "schedule side";
  /* The side column spans both rows; a flexible second row takes its extra
     height, so the schedule sits directly under the announcements instead of
     leaving a gap the size of the side column's overflow. */
  grid-template-rows: max-content minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
}
.home-fresh .home-announcements { grid-area: announce; }
.home-fresh .home-side { grid-area: side; }
.home-fresh .home-schedule { grid-area: schedule; margin-top: 0; }
.home-fresh .home-date { color: #063a3f; font-weight: 600; }

.home-fresh .home-card { border-top: 4px solid var(--accent, var(--ub-teal-mid)); }
.home-fresh .home-card > .home-section-title .home-title-icon { color: var(--accent, var(--ub-teal-ink)); }

.home-fresh .home-find-form { display: flex; gap: .45rem; }
.home-fresh .home-find-form .form-control,
.home-fresh .home-find-form .btn { border-radius: 8px; }

.home-fresh .home-date-dot { width: .6rem; height: .6rem; border-radius: 50%; flex: none; margin-right: .5rem; }
.home-fresh .home-date-when { flex: none; min-width: 5.6rem; }
.home-fresh .home-date-label { color: var(--ub-slate-dark); font-weight: 400; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.home-fresh .home-count-list li { display: grid; grid-template-columns: 7.2rem minmax(0, 1fr) 2rem; align-items: center; gap: .5rem; padding: .18rem 0; font-size: .85rem; }
.home-fresh .home-count-bar { height: .55rem; background: var(--ub-surface-2); border-radius: 999px; overflow: hidden; }
.home-fresh .home-count-fill-0 { background: var(--ub-teal-mid); }
.home-fresh .home-count-fill-2 { background: var(--ub-orange); }
.home-fresh .home-offhour-title { font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: var(--ub-slate); margin-bottom: .15rem; }

.home-fresh .home-schedule-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: .7rem; }
.home-fresh .home-schedule-hour-0 .home-schedule-hour-name { background: var(--ub-teal-tint); color: var(--ub-teal-deep); }
.home-fresh .home-schedule-hour-1 .home-schedule-hour-name { background: var(--ub-green-tint); color: var(--ub-green-ink); }
.home-fresh .home-schedule-hour-2 .home-schedule-hour-name { background: var(--ub-yellow-tint); color: var(--ub-amber-ink); }
.home-fresh .home-schedule-hour-0 { border-color: rgba(21, 188, 201, .35); }
.home-fresh .home-schedule-hour-1 { border-color: rgba(31, 168, 115, .35); }
.home-fresh .home-schedule-hour-2 { border-color: rgba(253, 175, 27, .45); }
.home-fresh .home-schedule-hour li { display: flex; flex-direction: column; padding: .28rem .6rem; }
.home-fresh .home-schedule-hour li:nth-child(even) { background: var(--ub-surface-3); }
.home-fresh .home-schedule-class { font-weight: 600; color: var(--ub-ink); }
.home-fresh .home-schedule-meta { font-size: .76rem; color: var(--ub-slate); line-height: 1.3; }

@media (max-width: 767.98px) {
  .home-fresh .home-columns { grid-template-columns: 1fr; grid-template-areas: "announce" "side" "schedule"; }
}

/* Samantha, 2026-09-08 23:01: "let's make the announcements half the width and
   put attendance up top alongside it." Six tracks: the top row splits in two,
   the rows under it two-thirds / one-third. */
.home-fresh .home-columns {
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-template-areas: "announce announce announce attendance attendance attendance" "schedule schedule schedule schedule side side" "extras extras extras extras side side";
  grid-template-rows: max-content max-content minmax(0, 1fr);
}
.home-fresh .home-attendance { grid-area: attendance; }
.home-fresh .home-extras { grid-area: extras; display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1rem; }
.home-fresh .home-badge {
  margin-left: auto;
  min-width: 1.35rem;
  padding: 0 .4rem;
  border-radius: 999px;
  background: var(--ub-red);
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  text-align: center;
  line-height: 1.35rem;
}
.home-fresh .home-payments-line { margin: 0 0 .35rem; font-size: .9rem; color: var(--ub-ink); }
.home-fresh .home-payments-line strong { color: var(--ub-teal-deep); }
.home-fresh .home-payments-unpaid { margin: 0; font-size: .82rem; color: var(--ub-slate-dark); line-height: 1.6; }
.home-fresh .home-birthday-list { list-style: none; margin: 0; padding: 0; font-size: .88rem; }
.home-fresh .home-birthday-list li { display: flex; gap: .5rem; align-items: baseline; padding: .28rem 0; border-bottom: 1px solid var(--ub-line-soft); }
.home-fresh .home-birthday-list li:last-child { border-bottom: 0; }
.home-fresh .home-birthday-list a { font-weight: 600; text-decoration: none; }
@media (max-width: 767.98px) {
  .home-fresh .home-columns { grid-template-columns: 1fr; grid-template-areas: "announce" "attendance" "side" "schedule" "extras"; grid-template-rows: none; }
}

.class-form .form-label { font-size: .78rem; margin-bottom: .15rem; color: var(--ub-slate-dark); }
.class-form-teachers { font-size: .9rem; padding: .3rem 0; color: var(--ub-ink); }
.class-form-teachers a { margin-left: .5rem; font-size: .8rem; }

/* Samantha, 2026-09-08 22:42: "all the lines at the tops of the boxes need to be
   changed to straight. Never curved lines." Square corners everywhere on the
   cards and the tiles inside them — her original rule, restored. */
.home-fresh .home-card, .ub-card,
.home-fresh .home-link-grid a, .home-fresh .home-schedule-hour, .home-fresh .home-add > summary,
.home-fresh .home-announce, .home-fresh .home-attention-action,
.home-fresh .home-find-form .form-control, .home-fresh .home-find-form .btn,
.home-fresh .home-add-form .form-control, .home-fresh .home-add-form .btn { border-radius: 0; }

/* Samantha, 2026-09-08 22:43: "I don't like the yellow in these spots" — the
   Hour 3 band, the orange headcount bars, the Birthdays edge. No yellow or
   orange on the homepage: teal, green, and the blue from her printed sheet
   ("the blue prints well on PDFs and we don't want to stray away from it"). */
.home-fresh .home-schedule-hour-2 .home-schedule-hour-name { background: #E4EDFB; color: #1d4ed8; }
.home-fresh .home-schedule-hour-2 { border-color: rgba(37, 99, 235, .30); }
.home-fresh .home-schedule-group { font-weight: 700; color: var(--ub-teal-ink); margin-right: .25rem; }
.home-fresh .home-attendance-day { font-size: .8rem; font-weight: 600; color: var(--ub-green-ink); }
.home-fresh .home-attendance-figures { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; margin-bottom: .6rem; }
.home-fresh .home-attendance-figures div { background: #F3FAFB; padding: .5rem .4rem; text-align: center; }
.home-fresh .home-attendance-figures strong { display: block; font-size: 1.4rem; line-height: 1.1; color: var(--ub-teal-deep); }
.home-fresh .home-attendance-figures span { font-size: .72rem; color: var(--ub-slate-dark); }
.home-fresh .home-absent-list { list-style: none; margin: 0; padding: 0; font-size: .86rem; }
.home-fresh .home-absent-list li { padding: .25rem 0; border-bottom: 1px solid var(--ub-line-soft); }
.home-fresh .home-absent-list li:last-child { border-bottom: 0; }
.home-fresh .home-absent-list a, .home-fresh .home-absent-adult { font-weight: 600; text-decoration: none; }
/* Samantha, 2026-09-08 22:57: "the announcements will have like 4-5 things
   listed out. I think the giant box is probably overkill." The empty state is
   one quiet line, so the box is only ever as tall as its announcements. */
.home-fresh .home-empty-state { display: flex; align-items: center; gap: .6rem; text-align: left; padding: .4rem 0 .2rem; }
.home-fresh .home-empty-state .bi { font-size: 1.4rem; margin: 0; }
.home-fresh .home-empty-title { font-size: .95rem; margin: 0; }
.home-fresh .home-empty-hint { display: none; }

/* The schedule strip, lined up. Samantha, 2026-09-08 23:00: "can we find a way
   to organize this a little bit better so it's easier to read at a glance?"
   Age group in a fixed column on the left of each hour, class and teachers
   beside it; an electives set is one row with its classes stacked. */
.home-fresh .home-schedule-rows { display: flex; flex-direction: column; }
.home-fresh .home-schedule-row {
  display: grid;
  grid-template-columns: 6.4rem minmax(0, 1fr);
  column-gap: .5rem;
  padding: .35rem .55rem;
  border-bottom: 1px solid var(--ub-line-soft);
}
.home-fresh .home-schedule-row:last-child { border-bottom: 0; }
.home-fresh .home-schedule-row-electives { background: var(--ub-teal-tint); }
.home-fresh .home-schedule-row-combined { background: var(--ub-surface-3); }
.home-fresh .home-schedule-groupcol {
  font-size: .74rem;
  font-weight: 700;
  color: var(--ub-teal-ink);
  line-height: 1.25;
  padding-top: .12rem;
}
.home-fresh .home-schedule-kind {
  display: block;
  font-size: .62rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ub-teal-deep);
}
.home-fresh .home-schedule-item { display: flex; flex-direction: column; padding: .1rem 0; }
.home-fresh .home-schedule-item + .home-schedule-item { border-top: 1px dashed var(--ub-teal-tint-deep); margin-top: .15rem; padding-top: .25rem; }
.home-fresh .home-schedule-class { font-weight: 600; color: var(--ub-ink); line-height: 1.2; }
.home-fresh .home-schedule-meta { font-size: .76rem; color: var(--ub-slate); line-height: 1.3; }
/* Samantha, 2026-09-08 23:05: "I would like the Hour 1, Hour 2, Hour 3 headers
   to be the same light gray so it looks like one cohesive schedule." */
.home-fresh .home-schedule-hour-0 .home-schedule-hour-name,
.home-fresh .home-schedule-hour-1 .home-schedule-hour-name,
.home-fresh .home-schedule-hour-2 .home-schedule-hour-name { background: var(--ub-surface-2); color: var(--ub-teal-deep); }
.home-fresh .home-schedule-hour-0, .home-fresh .home-schedule-hour-1, .home-fresh .home-schedule-hour-2 { border-color: var(--ub-rule); }
.allergy-text { font-weight: 600; color: var(--ub-red-deep); }
.allergy-phone { white-space: nowrap; }
/* Medical Info and Allergies on a phone: the four columns stack into one card per child.
   Samantha, 2026-09-09: "slightly too big for the screen and requires scrolling". */
@media (max-width: 767.98px) {
  .allergy-table thead { display: none; }
  .allergy-table, .allergy-table tbody, .allergy-table tr { display: block; width: 100%; }
  .allergy-table > tbody > tr { padding: 0.75rem 0; border-bottom: 1px solid var(--ub-line-soft); }
  .allergy-table > tbody > tr:last-child { border-bottom: 0; }
  .allergy-table > tbody > tr:hover > td { background: transparent; }
  .allergy-table > tbody > tr > td { display: block; border: 0; padding: 0; }
  .allergy-table td.allergy-child a { font-size: 1.1rem; font-weight: 700; }
  .allergy-table td.allergy-group, .allergy-table td.allergy-parent { display: inline; color: var(--ub-slate); font-size: 0.95rem; }
  .allergy-table td.allergy-group:not(:empty)::after { content: " · "; }
  .allergy-table td.allergy-text { margin-top: 0.35rem; font-size: 1.05rem; line-height: 1.4; }
}
@media print { .page-head .btn, .navbar { display: none !important; } .ub-card { box-shadow: none; border: 0; } }
/* Samantha, 2026-09-08 23:15: "I guess I don't like the gray - do this color
   instead" — the board's dark teal band, white text. */
.home-fresh .home-schedule-hour-0 .home-schedule-hour-name,
.home-fresh .home-schedule-hour-1 .home-schedule-hour-name,
.home-fresh .home-schedule-hour-2 .home-schedule-hour-name { background: var(--ub-teal-deep); color: #fff; }
.home-fresh .home-schedule-hour-name span { color: rgba(255, 255, 255, .8); }
/* The Classes table edits in place (Samantha, 2026-09-08 23:23). */
.inline-cell { min-width: 9rem; }
.inline-cell .form-select, .inline-cell .form-control { font-size: .82rem; }
.inline-fee { max-width: 7.5rem; }
.inline-cell.is-saved { background: var(--ub-green-tint); transition: background .2s; }
.inline-roster { display: inline-flex; align-items: center; gap: .15rem; white-space: nowrap; min-width: 0; }
.inline-capacity { width: 4.2rem; display: inline-block; font-size: .82rem; }
.session-form .form-label { font-size: .78rem; margin-bottom: .15rem; color: var(--ub-slate-dark); }
/* Groups & hours on one screen (Samantha, 2026-09-08 23:47). */
.setup-hint { font-size: .76rem; color: var(--ub-slate); margin-bottom: .45rem; }
#tab-setup .ub-card { padding: .6rem .75rem .7rem; }
#tab-setup .ub-card-title { margin-bottom: .5rem; padding-bottom: .4rem; }
#tab-setup .table > :not(caption) > * > * { padding: .22rem .35rem; }
#tab-setup .form-select-sm, #tab-setup .form-control-sm { font-size: .8rem; }
#tab-setup select[name="grade_level_start"], #tab-setup select[name="grade_level_end"] { min-width: 8.6rem; }
#tab-setup .table th { font-size: .72rem; }
/* The Classes table, condensed. Samantha, 2026-09-09 00:00: "I think we could
   condense this page a little better. The grade groups have pretty big text.
   Makes it so you have to scroll a lot." */
.classes-table > tbody > tr > td, .classes-table > thead > tr > th { padding: .28rem .4rem; }
.classes-table { font-size: .82rem; }
.classes-table .class-groups, .classes-table .class-period { white-space: nowrap; font-size: .78rem; color: var(--ub-slate-dark); }
.classes-table td a { font-size: .84rem; }
/* Small, but never so small that a box clips its own value — the mistake the
   first pass made with Room and Fee. */
.classes-table .class-title { white-space: nowrap; }
.classes-table .inline-cell { min-width: 0; }
.classes-table .inline-cell .form-select, .classes-table .inline-cell .form-control { font-size: .78rem; padding: .1rem .3rem; }
.classes-table .inline-cell .form-select { min-width: 7.4rem; padding-right: 1.4rem; }
.classes-table .inline-fee { max-width: 6rem; flex-wrap: nowrap; }
.classes-table .inline-fee .form-control { min-width: 3.6rem; }
.classes-table .inline-fee .input-group-text { padding: .1rem .3rem; font-size: .78rem; }
.classes-table .inline-capacity { width: 3.4rem; }
.classes-table .btn-sm { padding: .1rem .4rem; font-size: .75rem; }
.classes-table .form-check-input { margin-top: .1rem; }
.bulk-note { font-size: .74rem; color: var(--ub-slate); margin: 0 0 .45rem; }
.bulk-actions { display: grid; grid-template-columns: 1fr 1fr; gap: .3rem; }
.bulk-actions .btn { font-size: .76rem; padding: .25rem .3rem; }
.ub-card .form-label { font-size: .78rem; margin-bottom: .15rem; color: var(--ub-slate-dark); }

/* Outside teachers and time-boxed teaching (Samantha, 2026-09-09). */
.parent-chip.is-outside { border-color: var(--ub-green-mid); background: var(--ub-green-tint); }
.parent-chip .chip-from { font-size: .72rem; color: var(--ub-green-ink); }
.teacher-roster .parent-chip.is-outside { color: var(--ub-green-ink); font-weight: 600; }
.parent-chip .chip-dates { font-size: .7rem; color: var(--ub-slate); margin-left: .25rem; }
.parent-chip.is-finished { opacity: .5; text-decoration: line-through; }
.board-pool-link { font-size: .72rem; font-weight: 400; margin-left: .35rem; }
.board-pool-note { font-size: .78rem; margin: .5rem 0 0; }
.stint-list { border-top: 1px solid var(--ub-line-soft); margin-top: .75rem; padding-top: .6rem; }
.stint-title { font-size: .74rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: var(--ub-teal-ink); margin-bottom: .3rem; }
.stint-row { display: grid; grid-template-columns: minmax(0, 1fr) 9.5rem 9.5rem 7rem; gap: .4rem; align-items: center; padding: .18rem 0; }
.stint-row.is-finished .stint-name { opacity: .55; text-decoration: line-through; }
.stint-name { font-size: .85rem; }
.stint-state { font-size: .74rem; color: var(--ub-slate); }
.stint-note { font-size: .72rem; color: var(--ub-slate); margin: .35rem 0 0; }

/* "Here today, can sub" (docs/SAMANTHA_REQUESTS.md #48) — a same-day-only
   mark, distinct from the standing off-hour bench it sits alongside in this
   same list. --ub-yellow-tint is reserved for "today" (never a status), so
   reusing it here is the same visual language as attendance-day-today. */
.attendance-bench-here-today {
  background: var(--ub-yellow-tint);
  border-color: var(--ub-teal-mid);
}

/* Elective Rotations screen page (docs/SAMANTHA_REQUESTS.md §55). Samantha:
   "The electives are not mobile friendly at all for Merrilee. This should be
   a static page for viewing but able to actually be seen with the option to
   print the view that is currently here." Same rotation-sheet data as the
   printout, but one class per card, stacked full-width, names in a plain
   list — never a table, so there is nothing to scroll sideways on a phone. */
.elective-rotations-block { margin-bottom: 1.1rem; }
.elective-rotations-heading {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  margin: .7rem 0 .5rem;
}
.elective-rotations-heading:first-of-type { margin-top: 0; }
.elective-rotations-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: .6rem;
  margin-bottom: .3rem;
}
.elective-rotations-card {
  border: 1px solid var(--ub-line-soft);
  border-radius: 8px;
  padding: .55rem .7rem .65rem;
  background: var(--ub-surface);
}
.elective-rotations-card-title { font-weight: 700; color: var(--ub-ink); font-size: .95rem; }
.elective-rotations-card-count { font-size: .78rem; color: var(--ub-slate); margin-bottom: .35rem; }
.elective-rotations-names { list-style: none; margin: 0; padding: 0; font-size: .88rem; }
.elective-rotations-names li { padding: .12rem 0; border-top: 1px solid var(--ub-line-soft); }
.elective-rotations-names li:first-child { border-top: 0; }
.elective-rotations-empty { font-size: .82rem; color: var(--ub-slate); font-style: italic; margin: 0; }

/* Rotation page order (Samantha 2026-09-09 14:12): the current half first, the other
   half folded under a dropdown. */
.elective-rotations-now { font-size: 1.05rem; font-weight: 700; color: var(--ub-teal-ink); margin: 0.25rem 0 0.75rem; letter-spacing: 0.02em; text-transform: uppercase; }
.elective-rotations-later { margin-top: 1.25rem; }
.elective-rotations-later > summary { cursor: pointer; font-size: 1.05rem; font-weight: 700; color: var(--ub-teal-ink); letter-spacing: 0.02em; text-transform: uppercase; padding: 0.75rem 1rem; background: var(--ub-surface); border: 1px solid var(--ub-line-soft); border-radius: 0.5rem; list-style: none; }
.elective-rotations-later > summary::-webkit-details-marker { display: none; }
.elective-rotations-later > summary::before { content: "\25B8"; display: inline-block; margin-right: 0.5rem; transition: transform 0.15s; }
.elective-rotations-later[open] > summary::before { transform: rotate(90deg); }

/* §62 Room double-booking warning (Samantha 2026-09-09 14:41): "If I place a
   class in a room that already has someone in there that hour, it will
   double check with me that I meant to do it (not necessarily restrict it,
   but alert me)." A question, not an error — amber throughout. */
.room-clash-banner {
  background: var(--ub-amber-tint);
  border: 1px solid var(--ub-amber-line);
  color: var(--ub-amber-ink);
  border-radius: 0.5rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: 0.75rem;
}
.room-clash {
  display: block;
  color: var(--ub-amber-ink);
  font-size: 0.78rem;
  font-weight: 600;
  margin-top: 0.2rem;
  /* Phone width must not break (HOUSE_STYLE §2): wrap under the dropdown
     rather than pushing the row wider or truncating the other class's name. */
  white-space: normal;
  word-break: break-word;
}
.room-clash-alert {
  background: var(--ub-amber-tint);
  border: 1px solid var(--ub-amber-line);
  color: var(--ub-amber-ink);
  border-radius: 0.5rem;
  padding: 0.65rem 0.9rem;
  font-size: 0.9rem;
  margin-bottom: 0.75rem;
}
.room-clash-alert .form-check-label { color: var(--ub-amber-ink); }
.elective-rotations-later[open] > summary { margin-bottom: 0.75rem; }

/* §63 Session payments, split into the two collections Samantha's §27 rule
   requires -- registration and this session's class fees -- never summed on
   one line. Samantha, 2026-09-09 14:55: "Can you break these fees down into
   2 different fees due... It would be nice if there was a better breakdown
   of the family amount due right on this page." */
.fee-summary-row {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: 1rem;
}
.fee-summary-card {
  flex: 1 1 220px;
  background: var(--ub-surface);
  border: 1px solid rgba(11, 74, 80, .10);
  border-radius: 12px;
  box-shadow: 0 4px 14px rgba(20, 34, 35, .06);
  padding: .7rem .9rem;
}
.fee-summary-card-title {
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  margin-bottom: .35rem;
}
.fee-summary-card-figures { display: flex; gap: .9rem; flex-wrap: wrap; font-size: .85rem; }
.fee-summary-card-figures strong { display: block; font-size: 1.05rem; color: var(--ub-ink); }
.fee-summary-card-figures .is-outstanding strong { color: var(--ub-amber-ink); }

.fee-family-name { font-weight: 700; }

.fee-card-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.1rem;
}
@media (max-width: 640px) {
  .fee-card-columns { grid-template-columns: 1fr; }
}
.fee-collection + .fee-collection {
  border-top: 1px solid var(--ub-line-soft);
  padding-top: .85rem;
  margin-top: .1rem;
}
@media (min-width: 641px) {
  .fee-collection + .fee-collection { border-top: 0; padding-top: 0; }
}
.fee-collection-title {
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 700;
  color: var(--ub-teal-ink);
  margin-bottom: .5rem;
}
.fee-line {
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  font-size: .9rem;
  padding: .12rem 0;
}
.fee-child-block { margin-bottom: .6rem; }
.fee-child-name { font-weight: 700; font-size: .88rem; color: var(--ub-ink); }
.fee-child-subtotal { font-weight: 600; color: var(--ub-slate-dark); }
.fee-free-line { font-size: .82rem; color: var(--ub-slate); font-style: italic; margin-top: .2rem; }
.fee-total {
  display: flex;
  justify-content: space-between;
  font-weight: 700;
  border-top: 1px solid var(--ub-line-soft);
  margin-top: .4rem;
  padding-top: .4rem;
}
.fee-nothing-due { font-size: .85rem; color: var(--ub-slate); font-style: italic; margin-top: .5rem; }

.fee-form {
  display: flex;
  flex-direction: column;
  gap: .4rem;
  margin-top: .65rem;
}
.fee-form .form-control, .fee-form .form-select { font-size: .85rem; }
.fee-form-row { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; }
.fee-form-row > * { flex: 1 1 120px; min-width: 0; }

.fee-status-badge {
  display: inline-block;
  font-size: .74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  padding: .18rem .55rem;
  border-radius: 999px;
  margin-top: .5rem;
}
.fee-status-badge.is-unpaid { background: var(--ub-line-soft); color: var(--ub-slate-dark); }
.fee-status-badge.is-partial { background: var(--ub-amber-tint); color: var(--ub-amber-ink); }
.fee-status-badge.is-paid { background: var(--ub-green-tint); color: var(--ub-green-ink); }

/* ---------------------------------------------------------------------------
 * §64 — Edit Family form, compact refresh (2026-09-09). Samantha: "This page
 * could use a refresh on filling in information, more compact like
 * everything else we have worked on." ub-card sections, form-control-sm
 * rows; .is-check styling below is scoped copy of family_adult_edit's so a
 * Teaches/Can sub pair sits on one line under each parent's name.
 * ------------------------------------------------------------------------- */
.family-form .is-check {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .85rem;
  font-weight: 400;
  color: var(--ub-slate-dark);
}
.family-form details.ub-card > summary.ub-card-title {
  cursor: pointer;
  list-style: none;
}
.family-form details.ub-card > summary.ub-card-title::-webkit-details-marker { display: none; }
