/* ==========================================================================
   Crown Heights Hatzalah — member app
   Duty-board design system. Two typefaces, two weights, one accent, no shadows.

   Structure
     1. Tokens
     2. Bootstrap variable overrides
     3. Reset and base
     4. Typography
     5. Primitives — card, button, input, switch, badge, pill, status dot
     6. App shell — header, tabs, page
     7. Home
     8. Codes
     9. My Info
    10. Status roster
    11. Nightwatch
    12. CAR-1
    13. Info / reference
    14. Admin
    15. Holiday roster
    16. Dialog, toast, overlay
    17. Utilities and motion
   ========================================================================== */

/* 1. Tokens ============================================================== */

:root {
  /* Neutral ramp. One ramp, no near-duplicates. */
  --ink:          #14181d;   /* body text                      */
  --ink-2:        #545c66;   /* secondary text                 */
  --ink-3:        #838c98;   /* labels, metadata, placeholders  */
  --line:         #e2e5ea;   /* hairlines, every card border   */
  --line-strong:  #c9cfd8;   /* input borders, dividers        */
  --surface:      #ffffff;   /* cards                          */
  --surface-2:    #f6f7f9;   /* inset areas, table stripes     */
  --bg:           #f1f3f6;   /* page                           */

  /* The single accent. Hatzalah red. Primary actions only. */
  --accent:       #b71c1c;
  --accent-press: #8e1414;
  --accent-rgb:   183 28 28;

  /* Semantic status. Data encoding only — a dot and a word, never a fill.
     Desaturated to sit inside the neutral palette rather than compete
     with the accent. */
  --state-in:     #1c6b4f;   /* in town / covered / taken      */
  --state-out:    #8a5a10;   /* out of town / open / needed    */
  --state-off:    var(--ink-3);

  --ink-rgb:      20 24 29;

  /* Type. Two families. */
  --font-sans: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Two weights. There is no third. */
  --w-normal: 400;
  --w-medium: 500;

  /* Scale. 16px base, restrained. */
  --text-2xs:  0.6875rem; /* 11 — unit badges, table heads     */
  --text-xs:   0.75rem;   /* 12 — metadata, timestamps         */
  --text-sm:   0.8125rem; /* 13 — secondary, dense rows        */
  --text-md:   0.9375rem; /* 15 — body, controls               */
  --text-lg:   1.0625rem; /* 17 — card titles                  */
  --text-xl:   1.25rem;   /* 20 — section headings             */
  --text-2xl:  1.625rem;  /* 26 — page titles                  */
  --text-3xl:  2.25rem;   /* 36 — the one big number           */

  /* Space. 4px grid, no exceptions. */
  --s1:  0.25rem;  /*  4 */
  --s2:  0.5rem;   /*  8 */
  --s3:  0.75rem;  /* 12 */
  --s4:  1rem;     /* 16 */
  --s5:  1.5rem;   /* 24 */
  --s6:  2rem;     /* 32 */
  --s7:  3rem;     /* 48 */

  /* Radius. Small and consistent — boundaries are drawn with lines. */
  --r-sm:   4px;
  --r-md:   6px;
  --r-pill: 999px;

  /* Touch. Both clear 44px; a gloved thumb at 3am. */
  --control-sm: 44px;
  --control-md: 52px;

  /* One page inset, shared by the container and the full-bleed tab strip
     so the first tab lines up with the page title beneath it. */
  --page-pad: var(--s4);

  --rule: 1px solid var(--line);
  --focus: 0 0 0 2px rgb(var(--accent-rgb) / 0.9);
  --t: 120ms ease;
}

/* 2. Bootstrap variable overrides ======================================== */
/* Set Bootstrap's own variables rather than fighting its selectors. */

:root {
  --bs-body-font-family: var(--font-sans);
  --bs-body-font-size: var(--text-md);
  --bs-body-color: var(--ink);
  --bs-body-bg: var(--bg);
  --bs-font-monospace: var(--font-mono);
  --bs-border-color: var(--line);
  --bs-border-radius: var(--r-md);
  --bs-border-radius-sm: var(--r-sm);
  --bs-border-radius-lg: var(--r-md);
  --bs-border-radius-xl: var(--r-md);
  --bs-primary: var(--accent);
  --bs-danger: var(--accent);
  --bs-danger-rgb: var(--accent-rgb);
  --bs-link-color: var(--accent);
  --bs-link-hover-color: var(--accent-press);
  --bs-secondary-color: var(--ink-2);
  --bs-tertiary-color: var(--ink-3);
  --bs-box-shadow: none;
  --bs-box-shadow-sm: none;
  --bs-box-shadow-lg: none;
}

/* 3. Reset and base ====================================================== */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: var(--w-normal);
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-variant-numeric: tabular-nums;
}

img { max-width: 100%; display: block; }

hr {
  border: 0;
  border-top: var(--rule);
  margin: var(--s4) 0;
  opacity: 1;
}

::placeholder { color: var(--ink-3); opacity: 1; font-family: var(--font-sans); word-spacing: 0.04em; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: none;
  border-radius: var(--r-sm);
}

/* showView() moves focus to the destination heading. That is correct for
   screen readers, but a heading is not an interactive target, so give it a
   quiet marker rather than a full control ring. */
h1:focus-visible, h2:focus-visible, h3:focus-visible,
[tabindex="-1"]:focus-visible {
  outline: none;
  box-shadow: none;
}

::selection { background: rgb(var(--accent-rgb) / 0.16); }

/* 4. Typography ========================================================== */
/* Hierarchy is size, colour and the sans/mono switch. Never a third weight. */

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: var(--w-medium);
  line-height: 1.2;
  letter-spacing: -0.011em;
  color: var(--ink);
}

h1, .h1 { font-size: var(--text-2xl); letter-spacing: -0.02em; }
h2, .h2 { font-size: var(--text-xl); letter-spacing: -0.014em; }
h3, .h3 { font-size: var(--text-lg); }
h4, .h4 { font-size: var(--text-md); }
h5, .h5,
h6, .h6 { font-size: var(--text-sm); }

p { margin: 0 0 var(--s3); max-width: 68ch; }
p:last-child { margin-bottom: 0; }

strong, b { font-weight: var(--w-medium); }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* Mono is for data — unit designators, codes, times, dates, counts.
   Not for labels. Monospacing every label is the tell; monospacing the
   actual alphanumerics is the job. */
.mono,
.unit-code {
  font-family: var(--font-mono);
  font-feature-settings: "zero" 1; /* slashed zero: 0 vs O at 3am */
  letter-spacing: -0.01em;
}

/* The one place caps are allowed: real unit designators (CH51), which are
   uppercase in the radio vernacular, not a styling choice. */
.unit-code { text-transform: uppercase; }

/* A quiet label. Sentence case, not a tracked-out eyebrow. */
.field-label,
.home-eyebrow,
.info-row-label,
.address-detail-label,
.admin-stat-label,
.hero-stat-label,
.home-stat-label,
.nightwatch-count-label,
.nightwatch-night-label,
.holiday-roster-column-title {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-normal);
  line-height: 1.4;
  color: var(--ink-3);
  letter-spacing: 0;
  text-transform: none;
  margin: 0;
}

.text-muted,
.home-muted,
.small,
small {
  color: var(--ink-3) !important;
  font-size: var(--text-sm);
}

.text-danger { color: var(--accent) !important; }

/* 5. Primitives ========================================================== */

/* --- Card. One card. 1px border, no shadow, 6px radius. ----------------- */
.ch-card,
.section-card,
.home-panel,
.admin-settings-card,
.roster-card,
.info-callout,
.nightwatch-info-card,
.unit-setup-panel,
.admin-period-card,
.holiday-roster-card,
.address-detail-card,
.code-address-card,
.nightwatch-tonight-card,
.nightwatch-date-card {
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-md);
  box-shadow: none;
  padding: var(--s4);
}

.ch-card-tight { padding: var(--s3); }
.ch-card-flush { padding: 0; overflow: hidden; }

/* Card header: title left, action right, hairline under. */
.home-panel-title,
.admin-settings-heading,
.roster-toolbar,
.holiday-roster-header,
.address-detail-header,
.nightwatch-night-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin: 0 0 var(--s3);
  padding-bottom: var(--s3);
  border-bottom: var(--rule);
}

.home-panel-title h2,
.admin-settings-heading h2,
.roster-title {
  font-size: var(--text-md);
  font-weight: var(--w-medium);
  letter-spacing: -0.008em;
}

/* --- Button. Three intents, two sizes. Both clear 44px. ----------------- */
.btn {
  --bs-btn-box-shadow: none;
  --bs-btn-focus-box-shadow: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--control-sm);
  padding: 0 var(--s4);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: var(--w-medium);
  line-height: 1;
  letter-spacing: -0.006em;
  --bs-btn-border-width: 1px;
  border-style: solid;
  border-width: 1px;
  border-radius: var(--r-md);
  box-shadow: none;
  transition: background var(--t), border-color var(--t), color var(--t);
}

.btn:focus-visible { box-shadow: var(--focus); }

.btn-primary,
.btn-danger {
  --bs-btn-bg: var(--accent);
  --bs-btn-border-color: var(--accent);
  --bs-btn-hover-bg: var(--accent-press);
  --bs-btn-hover-border-color: var(--accent-press);
  --bs-btn-active-bg: var(--accent-press);
  --bs-btn-active-border-color: var(--accent-press);
  --bs-btn-color: #fff;
  --bs-btn-hover-color: #fff;
  --bs-btn-active-color: #fff;
  --bs-btn-disabled-bg: var(--line-strong);
  --bs-btn-disabled-border-color: var(--line-strong);
  --bs-btn-disabled-color: #fff;
}

.btn-outline-danger,
.btn-outline-primary,
.btn-outline-secondary,
.btn-secondary,
.btn-light {
  --bs-btn-bg: var(--surface);
  --bs-btn-border-color: var(--line-strong);
  --bs-btn-color: var(--ink);
  --bs-btn-hover-bg: var(--surface-2);
  --bs-btn-hover-border-color: var(--ink-3);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-active-bg: var(--surface-2);
  --bs-btn-active-border-color: var(--ink-3);
  --bs-btn-active-color: var(--ink);
  --bs-btn-disabled-bg: var(--surface);
  --bs-btn-disabled-border-color: var(--line);
  --bs-btn-disabled-color: var(--ink-3);
}

.btn-link {
  --bs-btn-color: var(--accent);
  --bs-btn-hover-color: var(--accent-press);
  min-height: auto;
  padding: 0;
  text-decoration: none;
}
.btn-link:hover { text-decoration: underline; text-underline-offset: 2px; }

.btn-sm {
  min-height: var(--control-sm);
  padding: 0 var(--s3);
  font-size: var(--text-sm);
  border-radius: var(--r-sm);
}

.btn-lg {
  min-height: var(--control-md);
  padding: 0 var(--s5);
  font-size: var(--text-md);
}

/* --- Input. One spec. --------------------------------------------------- */
.form-control,
.form-select,
.app-search-input,
.admin-unit-input {
  min-height: var(--control-sm);
  padding: var(--s2) var(--s3);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  font-weight: var(--w-normal);
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  box-shadow: none;
  transition: border-color var(--t);
}

.form-control:focus,
.form-select:focus,
.app-search-input:focus,
.admin-unit-input:focus {
  border-color: var(--accent);
  box-shadow: var(--focus);
  outline: none;
}

/* Codes, unit numbers and dates are typed as data — set them in mono. */
.app-search-input,
.admin-unit-input,
input[type="date"].form-control,
input[type="tel"].form-control,
input[type="number"].form-control {
  font-family: var(--font-mono);
  font-feature-settings: "zero" 1;
}

.form-label {
  display: block;
  margin-bottom: var(--s1);
  font-size: var(--text-xs);
  font-weight: var(--w-normal);
  color: var(--ink-3);
}

/* --- Switch. Two markup patterns exist in this app; both are supported.
       A: a bare <input class="app-switch" type="checkbox" role="switch">  (admin)
       B: <input type="checkbox"> + <span class="ch-switch-track">        (Nightwatch)

   Pattern A previously drew its knob with ::after — pseudo-elements do not
   render on <input>, so the knob was invisible and `:checked` was never
   styled at all (the old rules keyed off .is-on / [aria-checked], which
   nothing sets). Pattern B left the native checkbox visible next to the
   track, which is the stray box that appeared to "take over" the toggle. --- */

/* Shared track geometry. */
input.app-switch,
.ch-switch-track,
.nightwatch-toggle-track {
  position: relative;
  flex: 0 0 46px;
  width: 46px;
  height: 28px;
  margin: 0;
  background-color: var(--line-strong);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  box-shadow: none;
  cursor: pointer;
  transition: background-color var(--t);
}

/* Pattern A — knob drawn as a background image, the only way to put a knob
   inside an <input>. */
input.app-switch {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='10' cy='10' r='10' fill='%23fff'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 3px center;
  background-size: 20px 20px;
  transition: background-color var(--t), background-position var(--t);
}
input.app-switch:checked {
  background-color: var(--accent);
  background-position: 23px center;
}
input.app-switch:focus-visible { box-shadow: var(--focus); outline: none; }
input.app-switch:disabled { opacity: 0.5; cursor: not-allowed; }

/* Pattern B — the input is the control, so keep it focusable and hit-testable
   but visually hidden; the sibling span is the painted track. */
.nightwatch-month-toggle > input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  pointer-events: none;
}

.ch-switch-track::after,
.nightwatch-toggle-track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  background: var(--surface);
  border-radius: 50%;
  transition: transform var(--t);
}

input[type="checkbox"]:checked + .ch-switch-track,
input[type="checkbox"]:checked + .nightwatch-toggle-track { background-color: var(--accent); }

input[type="checkbox"]:checked + .ch-switch-track::after,
input[type="checkbox"]:checked + .nightwatch-toggle-track::after { transform: translateX(18px); }

input[type="checkbox"]:focus-visible + .ch-switch-track,
input[type="checkbox"]:focus-visible + .nightwatch-toggle-track { box-shadow: var(--focus); }

/* Bootstrap's own form-switch, where it is used. */
.form-switch .form-check-input {
  width: 46px;
  height: 28px;
  background-color: var(--line-strong);
  border-color: transparent;
  box-shadow: none;
}
.form-switch .form-check-input:checked { background-color: var(--accent); border-color: transparent; }
.form-check-input:focus { box-shadow: var(--focus); border-color: transparent; }

/* --- Unit badge. Real data, so mono and uppercase. ---------------------- */
.home-member-badge,
.nightwatch-unit-badge,
.holiday-member-badge,
.unit-profile-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 46px;
  height: 26px;
  padding: 0 var(--s2);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--w-medium);
  font-feature-settings: "zero" 1;
  text-transform: uppercase;
  letter-spacing: 0;
  color: var(--ink);
  background: var(--surface-2);
  border: var(--rule);
  border-radius: var(--r-sm);
  white-space: nowrap;
}

/* --- Status dot. The whole of the semantic colour budget. --------------- */
.status-icon,
.home-status-pill::before,
.home-open-pill::before,
.info-als-pill::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--state-off);
}

.is-covered .status-icon,
.is-taken .status-icon,
.in .status-icon,
.status-choice-in .status-icon { background: var(--state-in); }

.is-open .status-icon,
.is-needed .status-icon,
.out .status-icon,
.status-choice-out .status-icon { background: var(--state-out); }

.home-status-pill,
.home-open-pill,
.nightwatch-open-badge,
.info-als-pill,
.code-pill,
.admin-assign-status,
.carwatch-open {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: 2px var(--s2);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-normal);
  color: var(--ink-2);
  background: transparent;
  border: var(--rule);
  border-radius: var(--r-sm);
  white-space: nowrap;
}

.home-open-pill,
.nightwatch-open-badge,
.carwatch-open { color: var(--state-out); border-color: var(--state-out); }

/* Codes are the payload of the Codes screen — mono, and the only place
   a value gets its own weight. */
.code-pill {
  font-family: var(--font-mono);
  font-feature-settings: "zero" 1;
  font-size: var(--text-sm);
  font-weight: var(--w-medium);
  color: var(--ink);
  padding: var(--s1) var(--s2);
  background: var(--surface-2);
}

.code-pill-empty { color: var(--ink-3); font-weight: var(--w-normal); }

/* 6. App shell =========================================================== */

.app-mobile-shell {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--bg);
}

/* Header: a thin bar with a hairline. Not a floating card. */
.app-top-shell {
  position: sticky;
  top: 0;
  z-index: 1030;
  background: var(--surface);
  border-bottom: var(--rule);
  padding-top: env(safe-area-inset-top);
}

.app-header-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--s3) var(--page-pad);
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.app-brand-lockup {
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
  color: var(--ink);
  text-decoration: none;
  min-height: var(--control-sm);
}
.app-brand-lockup:hover { text-decoration: none; }

.app-brand-icon img { width: 32px; height: 32px; }

.app-brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}
/* The wordmark is a logo, so caps here are the mark, not a label style. */
.app-brand-text span {
  font-size: var(--text-2xs);
  font-weight: var(--w-normal);
  letter-spacing: 0.08em;
  color: var(--ink-3);
}
.app-brand-text strong {
  font-size: var(--text-md);
  font-weight: var(--w-medium);
  letter-spacing: 0.02em;
  color: var(--ink);
}

.app-header-actions { display: flex; align-items: center; gap: var(--s2); }

/* Menu button: three rules, no icon font. */
.app-menu-button {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: var(--control-sm);
  height: var(--control-sm);
  padding: 0 12px;
  background: none;
  border: var(--rule);
  border-radius: var(--r-md);
  cursor: pointer;
}
.app-menu-button span {
  display: block;
  height: 1px;
  background: var(--ink);
}
.app-menu-button:hover { background: var(--surface-2); }

/* Dropdown */
.dropdown-menu {
  --bs-dropdown-bg: var(--surface);
  --bs-dropdown-border-color: var(--line);
  --bs-dropdown-border-radius: var(--r-md);
  --bs-dropdown-link-color: var(--ink);
  --bs-dropdown-link-hover-bg: var(--surface-2);
  --bs-dropdown-link-active-bg: var(--surface-2);
  --bs-dropdown-link-active-color: var(--ink);
  --bs-dropdown-font-size: var(--text-md);
  box-shadow: none;
  border: var(--rule);
  padding: var(--s1);
  min-width: 260px;
}
.dropdown-item {
  display: flex;
  align-items: center;
  min-height: var(--control-sm);
  padding: 0 var(--s3);
  border-radius: var(--r-sm);
}
.dropdown-divider { border-top: var(--rule); margin: var(--s1) 0; }

/* Bottom nav. Thumb-reachable: the whole point of this app is one-handed use
   at 3am, and the top of a phone is the furthest thing from a thumb.
   Exactly one of Night / CAR-1 is ever visible (feature flag), so this is
   always six items. */
.app-bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1040;
  background: var(--surface);
  border-top: var(--rule);
  padding-bottom: env(safe-area-inset-bottom);
}

#mainTabs.nav {
  display: flex;
  flex-wrap: nowrap;
  gap: 0 !important;
  max-width: 1100px;
  margin: 0 auto;
  padding: 0;
  list-style: none;
}

#mainTabs .nav-item { flex: 1 1 0; min-width: 0; }

#mainTabs .nav-link {
  --bs-nav-link-padding-x: 0;
  --bs-nav-link-padding-y: 0;
  --bs-nav-pills-border-radius: 0;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 56px;
  padding: var(--s2) var(--s1);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--w-normal);
  letter-spacing: 0.004em;
  word-spacing: 0.06em;
  text-align: center;
  color: var(--ink-3);
  background: none !important;
  border: 0;
  border-radius: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: color var(--t);
}

/* Active state is a rule on the top edge, against the nav's own hairline. */
#mainTabs .nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -1px;
  height: 2px;
  background: transparent;
}

#mainTabs .nav-link:hover { color: var(--ink-2); }

#mainTabs .nav-link.active {
  color: var(--ink);
  font-weight: var(--w-medium);
}
#mainTabs .nav-link.active::after { background: var(--accent); }

#mainTabs .nav-link:focus-visible {
  box-shadow: none;
  outline: 2px solid var(--accent);
  outline-offset: -3px;
}

/* Content has to clear the bar. 56px + hairline + safe area. */
.app-mobile-shell { padding-bottom: calc(57px + env(safe-area-inset-bottom)); }

/* Anything else pinned to the bottom stacks above the nav. */
.app-save-toast { bottom: calc(57px + var(--s3) + env(safe-area-inset-bottom)); }
.admin-settings-savebar { bottom: calc(57px + env(safe-area-inset-bottom)); }

@media (max-width: 400px) {
  #mainTabs .nav-link { font-size: var(--text-xs); padding: var(--s2) 2px; }
}

/* Page */
main.container,
.app-page-shell {
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--s5) var(--page-pad) calc(var(--s7) + env(safe-area-inset-bottom));
}

.app-home-page,
.in-town-page,
.nightwatch-page,
.admin-page { display: block; }

/* Page head: title flush left, meta underneath in mono. No hero, no centring. */
.section-title,
.hero-title,
.nightwatch-title {
  font-size: var(--text-2xl);
  font-weight: var(--w-medium);
  letter-spacing: -0.02em;
  color: var(--ink);
  text-align: left;
}

.hero-copy,
.nightwatch-hero-copy > p {
  font-size: var(--text-md);
  color: var(--ink-2);
  max-width: 60ch;
}

/* 7. Home ================================================================ */

/* The greeting is not a hero card. It is a line of text. */
.home-hero-card {
  padding: 0;
  margin-bottom: var(--s5) !important;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.home-hero-content { display: block; text-align: left; }

.home-greeting {
  font-size: var(--text-2xl);
  font-weight: var(--w-medium);
  letter-spacing: -0.02em;
  margin-bottom: var(--s1);
}

.home-date-line {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-feature-settings: "zero" 1;
  color: var(--ink-3);
  margin: 0;
}

/* The quick-action link row is gone — it duplicated the bottom nav. The
   greeting block now carries the rule that used to sit beneath it. */
.home-hero-card {
  padding-bottom: var(--s4) !important;
  border-bottom: var(--rule) !important;
}

/* Asymmetric grid. Not four equal cards. */
.home-dashboard-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s4);
}

@media (min-width: 768px) {
  .home-dashboard-grid {
    grid-template-columns: 7fr 5fr;
    align-items: start;
  }
  /* Your own status is what you came for, so it takes the wide column.
     It is not forced full-width: with Nightwatch off there are only two
     panels, and spanning both columns left the 5fr column empty. */
  #homeStatusPanel { grid-column: 1; }
}

/* The one bold element: duty rows carry a 3px accent rule on the left. */
.home-status-summary-card,
.home-current-status-item,
.home-shift-mini,
.nightwatch-shift-row,
.carwatch-unit,
.home-reminder-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--control-sm);
  padding: var(--s3) var(--s3) var(--s3) var(--s4);
  background: var(--surface-2);
  border: var(--rule);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--r-sm);
  box-shadow: none;
}

.home-status-summary-card { border-left-color: var(--accent); }

.is-covered, .is-taken, .in { border-left-color: var(--state-in) !important; }
.is-open, .is-needed, .out { border-left-color: var(--state-out) !important; }
.is-urgent, .is-attention { border-left-color: var(--accent) !important; }

.home-member-mini { display: flex; align-items: center; gap: var(--s3); }

.home-member-name {
  font-size: var(--text-md);
  font-weight: var(--w-medium);
  color: var(--ink);
  line-height: 1.3;
}

.home-member-unit {
  font-size: var(--text-sm);
  color: var(--ink-3);
}

.home-current-status-list {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.home-current-status-main {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}

.home-current-status-title {
  font-size: var(--text-md);
  font-weight: var(--w-normal);
  color: var(--ink);
}

.home-current-status-date {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-feature-settings: "zero" 1;
  color: var(--ink-3);
  white-space: nowrap;
}

/* The one big number. Mono, because it is a count. */
.home-nightwatch-progress-card,
.nightwatch-count-card,
.admin-stat-card,
.hero-stat-card,
.home-stat-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s1);
  padding: var(--s3);
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-sm);
  box-shadow: none;
  text-align: left;
}

.home-nightwatch-progress-number,
.nightwatch-count-number,
.admin-stat-number,
.hero-stat-number,
.home-stat-number {
  font-family: var(--font-mono);
  font-size: var(--text-3xl);
  font-weight: var(--w-normal);
  font-feature-settings: "zero" 1;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.is-zero .home-nightwatch-progress-number,
.is-zero .nightwatch-count-number,
.is-zero .hero-stat-number { color: var(--ink-3); }

.home-nightwatch-detail,
.nightwatch-hero-coverage {
  display: flex;
  gap: var(--s4);
  margin-top: var(--s2);
  padding-top: var(--s2);
  border-top: var(--rule);
  width: 100%;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-feature-settings: "zero" 1;
  color: var(--ink-3);
}

.home-nightwatch-list,
.carwatch-units,
.nightwatch-available-month-list {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.home-shift-time,
.nightwatch-shift-time,
.nightwatch-calendar-shift-time,
.carwatch-date,
.nightwatch-night-date,
.holiday-period-dates,
.admin-period-dates,
.info-member-unit,
.nightwatch-month-current {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-feature-settings: "zero" 1;
  color: var(--ink-2);
  white-space: nowrap;
}

.home-shift-person,
.nightwatch-shift-member,
.nightwatch-calendar-shift-person {
  font-size: var(--text-md);
  color: var(--ink);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.home-stat-grid,
.hero-stat-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s2);
}
.home-stat-grid-two { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.hero-stat-button,
.home-stat-button {
  cursor: pointer;
  transition: border-color var(--t);
}
.hero-stat-button:hover,
.home-stat-button:hover { border-color: var(--ink-3); }

.hero-stat-card-muted { background: var(--surface-2); }

.home-status-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.home-status-action-wrap { display: flex; gap: var(--s2); }

.home-panel-action-btn { flex: 0 0 auto; }

/* 8. Codes =============================================================== */
/* The payload screen. Dense rows, address left, codes right, hairline between. */

/* Legend and code-pill colours are defined once, in the review-pass section
   near the end of this file. Only the shared swatch geometry lives here. */
.code-legend-swatch {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--ink-3);
}
.code-pill-elevator { background: transparent; }

.code-directory-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-md);
  overflow: hidden;
}

.code-address-card {
  border: 0;
  border-bottom: var(--rule);
  border-radius: 0;
  padding: var(--s3) var(--s4);
  background: var(--surface);
}
.code-address-card:last-child { border-bottom: 0; }

.code-address-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: var(--control-sm);
}

.code-address-title {
  font-size: var(--text-md);
  font-weight: var(--w-normal);
  color: var(--ink);
  min-width: 0;
}

.code-badge-row { display: flex; gap: var(--s2); flex-wrap: wrap; }

.code-address-note {
  font-size: var(--text-sm);
  color: var(--ink-3);
  margin-top: var(--s1);
}

.code-arrow { color: var(--ink-3); flex: 0 0 auto; }

.is-clickable { cursor: pointer; }
.is-clickable:hover { background: var(--surface-2); }

.clear-icon {
  position: absolute;
  right: var(--s2);
  top: 50%;
  transform: translateY(-50%);
  width: var(--control-sm);
  height: var(--control-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xl);
  line-height: 1;
  color: var(--ink-3);
  background: none;
  border: 0;
  cursor: pointer;
}
.clear-icon:hover { color: var(--ink); }

.address-detail-header { align-items: flex-start; }
.address-detail-title { font-size: var(--text-lg); font-weight: var(--w-medium); }
.address-detail-body { display: flex; flex-direction: column; gap: var(--s3); }
.address-detail-codes { display: flex; flex-wrap: wrap; gap: var(--s2); }
.address-detail-note { font-size: var(--text-sm); color: var(--ink-2); }
.address-detail-img { border: var(--rule); border-radius: var(--r-sm); }

/* 9. My Info ============================================================= */

.unit-profile-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
}

.unit-profile-main { display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.unit-profile-title { font-size: var(--text-md); font-weight: var(--w-medium); }
.unit-profile-subtitle { font-size: var(--text-sm); color: var(--ink-3); }

.unit-match-list {
  display: flex;
  flex-direction: column;
  border: var(--rule);
  border-radius: var(--r-md);
  overflow: hidden;
}
.unit-match-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: var(--control-sm);
  padding: var(--s2) var(--s3);
  border-bottom: var(--rule);
  background: var(--surface);
}
.unit-match-item:last-child { border-bottom: 0; }
.unit-match-item:hover { background: var(--surface-2); }
.unit-match-name { font-size: var(--text-md); }
.unit-match-label {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--ink-3);
}

/* In / out choice: two equal targets, chosen state marked by rule + dot. */
.status-choice-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
}

.status-choice {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--control-md);
  padding: var(--s2) var(--s3);
  font-size: var(--text-md);
  font-weight: var(--w-normal);
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: border-color var(--t), color var(--t);
}
.status-choice:hover { border-color: var(--ink-3); }

.status-choice.active,
.status-choice[aria-pressed="true"] {
  color: var(--ink);
  font-weight: var(--w-medium);
  border-color: var(--ink);
  border-width: 2px;
}
.status-choice-in.active  { border-color: var(--state-in); }
.status-choice-out.active { border-color: var(--state-out); }

/* Admin feature toggles: one per row, title above description. Both were
   inline, so "Shabbos Status" ran straight into its own help text. */
.status-admin-options {
  display: flex;
  flex-direction: column;
  gap: 0;
  border: var(--rule);
  border-radius: var(--r-md);
  overflow: hidden;
}
.status-admin-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s3) var(--s4);
  font-size: var(--text-md);
  background: var(--surface);
  border: 0;
  border-bottom: var(--rule);
  border-radius: 0;
  cursor: pointer;
}
.status-admin-option:last-child { border-bottom: 0; }
.status-admin-option:hover { background: var(--surface-2); }
.status-admin-option > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.status-admin-option strong {
  font-size: var(--text-md);
  font-weight: var(--w-medium);
  color: var(--ink);
}
.status-admin-option small {
  font-size: var(--text-sm);
  color: var(--ink-3);
  word-spacing: 0.08em;
}

/* 10. Status roster ====================================================== */
/* Was a red gradient hero. Now a page head plus a stat strip. */

.in-town-hero {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  margin-bottom: var(--s5);
  padding: 0 0 var(--s4);
  background: none;
  border: 0;
  border-bottom: var(--rule);
  border-radius: 0;
  box-shadow: none;
  color: var(--ink);
}

.hero-badge {
  display: inline-block;
  margin-bottom: var(--s1);
  font-size: var(--text-xs);
  font-weight: var(--w-normal);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
  background: none;
  border: 0;
  padding: 0;
}

.hero-title { margin-bottom: var(--s2); }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s4); }

.roster-card { padding: 0; }
.roster-card .card-body { padding: var(--s4) !important; }
.roster-toolbar { align-items: flex-end; }

.holiday-member-row,
.info-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--control-sm);
  padding: var(--s2) var(--s3);
  background: var(--surface);
  border: 0;
  border-bottom: var(--rule);
  border-radius: 0;
  box-shadow: none;
}

.holiday-member-name,
.info-row-main {
  font-size: var(--text-md);
  color: var(--ink);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.empty-roster {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s2);
  padding: var(--s5) var(--s4);
  font-size: var(--text-md);
  color: var(--ink-3);
  background: var(--surface-2);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
}
.empty-roster-icon { display: none; }

/* 11. Nightwatch ========================================================= */

.nightwatch-hero {
  display: block;
  margin-bottom: var(--s5);
  padding: 0 0 var(--s4);
  background: none;
  border: 0;
  border-bottom: var(--rule);
  border-radius: 0;
  box-shadow: none;
  color: var(--ink);
}

.nightwatch-hero-layout {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s4);
}

.nightwatch-title { margin-bottom: var(--s2); }

.nightwatch-count-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s2);
  margin-bottom: var(--s4);
}

.nightwatch-month-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s4);
  padding-bottom: var(--s3);
  border-bottom: var(--rule);
}

.nightwatch-month-nav,
.nightwatch-month-stepper { display: flex; align-items: center; gap: var(--s2); }

.nightwatch-month-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-sm);
  height: var(--control-sm);
  color: var(--ink-2);
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.nightwatch-month-arrow:hover { background: var(--surface-2); border-color: var(--ink-3); }

.nightwatch-month-current {
  min-width: 9ch;
  text-align: center;
  font-size: var(--text-md);
  color: var(--ink);
}

.nightwatch-month-toggle { display: flex; align-items: center; gap: var(--s2); }
.nightwatch-toggle-text { font-size: var(--text-sm); color: var(--ink-2); }

/* Calendar: a list of nights, not a decorated grid. */
.nightwatch-calendar-grid,
.nightwatch-month-card-grid,
.nightwatch-upcoming-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: var(--s2);
}

.nightwatch-calendar-day,
.nightwatch-month-night-card {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  padding: var(--s3);
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-sm);
  box-shadow: none;
}

.nightwatch-calendar-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  padding-bottom: var(--s2);
  border-bottom: var(--rule);
}

.nightwatch-calendar-dayname {
  font-size: var(--text-xs);
  color: var(--ink-3);
}

.nightwatch-calendar-date {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  font-feature-settings: "zero" 1;
  color: var(--ink);
}

.nightwatch-calendar-shifts,
.nightwatch-month-shift-row {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.nightwatch-calendar-shift {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s2);
  min-height: 36px;
  padding: var(--s1) var(--s2);
  background: var(--surface-2);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--r-sm);
}

.nightwatch-shift-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
}

.nightwatch-available { border-left-color: var(--state-out) !important; }
.nightwatch-taken     { border-left-color: var(--state-in) !important; }
.nightwatch-blocked   { opacity: 0.5; }

.nightwatch-taken-change-btn { margin-left: auto; }

.nightwatch-night-heading { align-items: baseline; }
.nightwatch-night-date { font-size: var(--text-md); color: var(--ink); }
.nightwatch-member-corner { margin-left: auto; }
.nightwatch-mini-card { padding: var(--s2) var(--s3); border: var(--rule); border-radius: var(--r-sm); }
.nightwatch-month-message { font-size: var(--text-sm); color: var(--ink-3); }
.nightwatch-month-section { margin-top: var(--s5); }
.nightwatch-action-row { display: flex; flex-wrap: wrap; gap: var(--s2); }
.nightwatch-action-modal-meta {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--ink-3);
}

/* Feature flags. Behaviour preserved exactly: the CAR-1 read-only tab stands
   in while Nightwatch is off, so exactly one of the two is ever visible. */
body.nightwatch-off .nightwatch-feature { display: none !important; }
body:not(.nightwatch-off) .carwatch-feature { display: none !important; }

/* Feature gating sets the hidden attribute, but Bootstrap's display utilities
   carry !important and would otherwise keep a hidden element on screen. */
[hidden] { display: none !important; }
.admin-only-nav.d-none { display: none !important; }

/* 12. CAR-1 ============================================================== */

.carwatch-night-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  padding-bottom: var(--s2);
  margin-bottom: var(--s3);
  border-bottom: var(--rule);
}
.carwatch-night-title { font-size: var(--text-md); font-weight: var(--w-medium); }
.carwatch-night-sub { font-size: var(--text-xs); color: var(--ink-3); }

/* 13. Info / reference =================================================== */

.info-stack { display: flex; flex-direction: column; gap: var(--s4); }
.info-group { border: var(--rule); border-radius: var(--r-md); overflow: hidden; }
.info-group-title {
  padding: var(--s2) var(--s3);
  font-size: var(--text-xs);
  color: var(--ink-3);
  background: var(--surface-2);
  border-bottom: var(--rule);
}
.info-directory-list { display: flex; flex-direction: column; }
.info-row:last-child { border-bottom: 0; }
.info-row-label { flex: 0 0 auto; }
.info-row-note { font-size: var(--text-sm); color: var(--ink-3); }
.info-body { font-size: var(--text-md); color: var(--ink-2); }
.info-call { margin-left: auto; }
.info-member-unit { margin-left: auto; }

/* 14. Admin ============================================================== */

.admin-settings-stack { display: flex; flex-direction: column; gap: var(--s4); }
.admin-settings-heading-action { margin-left: auto; }
.admin-settings-savebar {
  position: sticky;
  bottom: 0;
  display: flex;
  justify-content: flex-end;
  gap: var(--s2);
  padding: var(--s3) 0;
  background: var(--bg);
  border-top: var(--rule);
}

.admin-summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s2);
}

.admin-stats-list { display: flex; flex-direction: column; }
.admin-stats-head,
.admin-stats-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 40px;
  padding: var(--s1) var(--s2);
  border-bottom: var(--rule);
}
.admin-stats-head {
  font-size: var(--text-xs);
  color: var(--ink-3);
  background: var(--surface-2);
}
.admin-stats-unit {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-feature-settings: "zero" 1;
}

.admin-period-card { margin-bottom: var(--s2); }
.admin-period-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  margin-bottom: var(--s2);
}
.admin-period-field,
.admin-season-field { display: flex; flex-direction: column; gap: var(--s1); }
.admin-period-dates {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}
.admin-period-remove { margin-left: auto; }
.admin-shift-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) 0;
  border-bottom: var(--rule);
}
.admin-shift-title { font-size: var(--text-md); }
.admin-shift-meta { font-size: var(--text-xs); color: var(--ink-3); }
.admin-shift-actions { margin-left: auto; display: flex; gap: var(--s2); }
.admin-uncovered-list { display: flex; flex-direction: column; gap: var(--s1); }

/* 15. Holiday roster ===================================================== */

.holiday-roster-section { margin-top: var(--s5); }
.holiday-roster-groups { display: flex; flex-direction: column; gap: var(--s4); }
.holiday-roster-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: var(--s4);
}
.holiday-roster-column { display: flex; flex-direction: column; gap: var(--s2); }
.holiday-roster-column-title { padding-bottom: var(--s1); border-bottom: var(--rule); }
.holiday-member-list {
  display: flex;
  flex-direction: column;
  border: var(--rule);
  border-radius: var(--r-md);
  overflow: hidden;
}
.holiday-member-row:last-child { border-bottom: 0; }
.holiday-period-name { font-size: var(--text-md); font-weight: var(--w-medium); }
.holiday-roster-stats { display: flex; gap: var(--s4); font-size: var(--text-xs); color: var(--ink-3); }
.holiday-mini-stat { font-family: var(--font-mono); font-feature-settings: "zero" 1; }
.holiday-section-heading { font-size: var(--text-md); font-weight: var(--w-medium); }
.holiday-list-empty { font-size: var(--text-sm); color: var(--ink-3); padding: var(--s3); }
.holiday-bulk-actions { display: flex; flex-wrap: wrap; gap: var(--s2); }
/* The bulk "all in / all out" toggles sit side by side... */
.holiday-status-options { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* ...but each Yom Tov period is its own row. This was a wrapping flex, which
   ran the periods together horizontally. */
.holiday-status-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  border: var(--rule);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
}
.holiday-status-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s2) var(--s3);
  padding: var(--s3);
  border-bottom: var(--rule);
}
.holiday-status-row:last-child { border-bottom: 0; }
.holiday-status-row > :first-child { min-width: 0; }
.holiday-status-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: 38px;
  min-width: 84px;
  padding: 0 var(--s3);
  font-size: var(--text-sm);
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  cursor: pointer;
  user-select: none;
  transition: border-color var(--t), color var(--t), background var(--t);
}
.holiday-status-option:hover { border-color: var(--ink-3); }

/* Selected. Bootstrap hides .btn-check, so this adjacent-sibling rule is the
   only thing that can show the choice. Previously absent, which is why
   in/out looked like it was not selecting. */
.btn-check:checked + .holiday-status-option {
  color: var(--ink);
  font-weight: var(--w-medium);
  border-width: 2px;
  padding: 0 calc(var(--s3) - 1px);
  background: var(--surface-2);
}
.btn-check:checked + .holiday-status-option-in  { border-color: var(--state-in);  color: var(--state-in); }
.btn-check:checked + .holiday-status-option-out { border-color: var(--state-out); color: var(--state-out); }

/* Keyboard focus has to be visible on the label, since the input is hidden. */
.btn-check:focus-visible + .holiday-status-option { box-shadow: var(--focus); }

/* A dot mirrors the semantic colour, matching the rest of the app. */
.holiday-status-option::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--line-strong);
  transition: background var(--t);
}
.btn-check:checked + .holiday-status-option-in::before  { background: var(--state-in); }
.btn-check:checked + .holiday-status-option-out::before { background: var(--state-out); }

/* 16. Dialog, toast, overlay ============================================= */

.modal-content {
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-md);
  box-shadow: none;
}
.modal-header,
.modal-footer {
  padding: var(--s3) var(--s4);
  border-color: var(--line);
}
.modal-body { padding: var(--s4); }
.modal-title { font-size: var(--text-lg); font-weight: var(--w-medium); }
.modal-backdrop.show { opacity: 0.4; }

.app-save-toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--s5) + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 1080;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s3) var(--s4);
  font-size: var(--text-sm);
  color: var(--surface);
  background: var(--ink);
  border-radius: var(--r-md);
  box-shadow: none;
}

.sync-overlay {
  position: fixed;
  inset: 0;
  z-index: 1090;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(var(--ink-rgb) / 0.4);
}

.app-sync-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s3);
  font-size: var(--text-sm);
  color: var(--ink);
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-md);
}

.alert {
  padding: var(--s3);
  font-size: var(--text-sm);
  color: var(--ink);
  background: var(--surface-2);
  border: var(--rule);
  border-left: 3px solid var(--ink-3);
  border-radius: var(--r-sm);
}
.alert-warning { border-left-color: var(--state-out); }
.alert-danger  { border-left-color: var(--accent); }
.alert-success { border-left-color: var(--state-in); }

.spinner-border {
  width: 1rem;
  height: 1rem;
  border-width: 2px;
  color: var(--ink-3) !important;
}

/* 17. Utilities and motion =============================================== */

.is-primary-action { font-weight: var(--w-medium); }
.is-actionable { cursor: pointer; }
.unset { color: var(--ink-3); }
.org { font-size: var(--text-xs); color: var(--ink-3); }

/* Responsive */
@media (max-width: 767.98px) {
  :root { --page-pad: var(--s3); }
  main.container,
  .app-page-shell { padding: var(--s4) var(--page-pad) var(--s7); }
  .home-stat-grid,
  .hero-stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 400px) {
  .status-choice-grid { grid-template-columns: 1fr; }
  .home-stat-grid,
  .hero-stat-grid { grid-template-columns: 1fr; }
  .nightwatch-calendar-shift { grid-template-columns: 1fr; }
  .home-current-status-date { margin-left: 0; }
  .home-current-status-item { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .app-top-shell,
  .app-bottom-nav,
  .btn { display: none !important; }
  .app-mobile-shell { padding-bottom: 0; }
  body { background: #fff; }
}

/* --- Bootstrap weight utilities are clamped into the two-weight system.
       .fw-bold and .fw-semibold appear 38 times in generated markup; rather
       than rewrite each call site, they resolve to medium. ---------------- */
.fw-bold,
.fw-semibold,
.fw-bolder,
.fw-medium { font-weight: var(--w-medium) !important; }
.fw-normal, .fw-light, .fw-lighter { font-weight: var(--w-normal) !important; }

.eyebrow {
  font-size: var(--text-xs);
  font-weight: var(--w-normal);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}

/* --- Coverage for classes generated in JS template strings --------------- */
.admin-yom-tov-periods { display: grid; gap: var(--s2); }
.admin-period-visible {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
}
.holiday-status-section { margin-top: var(--s5); padding-top: var(--s5); border-top: var(--rule); }
.home-nightwatch-progress-label {
  font-size: var(--text-sm);
  font-weight: var(--w-normal);
  color: var(--ink-3);
  text-align: left;
  overflow-wrap: anywhere;
}
.unit-match-action {
  flex: 0 0 auto;
  font-size: var(--text-sm);
  font-weight: var(--w-medium);
  color: var(--accent);
  white-space: nowrap;
}

/* --- First-run prompt. Was a 3px red border, 20px radius, large shadow and
       centred text. Now the same card as everything else. ----------------- */
.first-run-body { padding: var(--s4); }
.first-run-title { font-size: var(--text-lg); margin-bottom: var(--s2); }
.first-run-copy { font-size: var(--text-sm); color: var(--ink-2); margin-bottom: var(--s4); }


/* --- Optical tracking ---------------------------------------------------
   Plus Jakarta Sans has a narrow space glyph that closes up below ~14px
   ("Set your unit on My Info" ran together). Small sizes get looser word and
   letter spacing, large sizes get tighter — the normal optical adjustment,
   applied here by size rather than left to the face's defaults. */
body { word-spacing: 0.04em; }

.small, small,
.text-muted,
.field-label, .eyebrow,
.home-member-unit, .home-muted,
.info-row-note, .info-details,
.admin-shift-meta, .nightwatch-month-message,
.code-address-note, .address-detail-note,
.holiday-roster-stats, .holiday-list-empty,
.first-run-copy,
.btn-sm, .status-choice, .holiday-status-option, .status-admin-option,
.home-status-pill, .home-open-pill, .nightwatch-open-badge,
.info-als-pill, .admin-assign-status, .carwatch-open,
.nightwatch-toggle-text, .info-group-title, .admin-stats-head,
.home-nightwatch-progress-label,
.unit-profile-subtitle,
.carwatch-night-sub {
  word-spacing: 0.08em;
  letter-spacing: 0.004em;
}

/* Mono is monospaced — it already has a full-width space. Leave it alone. */
.mono, .unit-code,
[class*="-date"], [class*="-time"],
.app-search-input, .admin-unit-input,
.home-date-line, .admin-stats-unit,
.holiday-mini-stat, .nightwatch-action-modal-meta,
.home-nightwatch-progress-number, .nightwatch-count-number,
.admin-stat-number, .hero-stat-number, .home-stat-number {
  word-spacing: normal;
}

/* --- Info accordion. Was four separate cards each holding one <details>,
       with a summary rendering at inherited-small size and no touch target.
       Now one bordered group with hairline rows. ------------------------- */
.info-accordion {
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-md);
  overflow: hidden;
}
.info-accordion-item { border-bottom: var(--rule); }
.info-accordion-item:last-child { border-bottom: 0; }

.info-details { font-size: var(--text-md); color: var(--ink); }

.info-details > summary {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: var(--control-sm);
  padding: var(--s3) var(--s4);
  font-size: var(--text-md);
  font-weight: var(--w-normal);
  color: var(--ink);
  cursor: pointer;
  list-style: none;
  transition: background var(--t);
}
.info-details > summary::-webkit-details-marker { display: none; }
.info-details > summary:hover { background: var(--surface-2); }

/* Disclosure drawn as a rule, not an icon glyph. */
.info-details > summary::before {
  content: "";
  flex: 0 0 8px;
  width: 8px;
  height: 8px;
  border-right: 1px solid var(--ink-3);
  border-bottom: 1px solid var(--ink-3);
  transform: rotate(-45deg) translate(-1px, -1px);
  transition: transform var(--t);
}
.info-details[open] > summary::before { transform: rotate(45deg) translate(-2px, -2px); }
.info-details[open] > summary { border-bottom: var(--rule); }

.info-details > .info-body,
.info-details > div:not(summary) { padding: var(--s4); }

.info-body { font-size: var(--text-md); color: var(--ink-2); }
.info-body ul { margin: 0 0 var(--s3); padding-left: var(--s5); }
.info-body li { margin-bottom: var(--s1); }
.info-body p { margin-bottom: var(--s3); }

/* ==========================================================================
   Review pass — alignment, density and mobile fixes
   ========================================================================== */

/* 1. Status tags sit in their own fixed column, left-aligned, so they line up
      down the list instead of tracking the width of each period name. */
.home-current-status-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 104px;
  align-items: center;
  gap: var(--s3);
}
.home-current-status-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 168px;
  align-items: baseline;
  gap: var(--s3);
  min-width: 0;
}
.home-current-status-title { min-width: 0; overflow-wrap: anywhere; }
.home-current-status-date { margin-left: 0; justify-self: start; }
.home-status-pill { justify-self: start; }

@media (max-width: 560px) {
  .home-current-status-item { grid-template-columns: minmax(0, 1fr) 92px; }
  .home-current-status-main { grid-template-columns: 1fr; gap: 0; }
}

/* 2 + 13. Nightwatch shift rows. The grid was three columns but the markup
      only ever emits two children (badge+text wrapper, then the action), so
      the action landed in the middle column and the row read as broken.
      Two columns, action in a fixed left-aligned column. */
.nightwatch-shift-row,
.nightwatch-month-shift-row.nightwatch-shift-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 88px;
  align-items: center;
  gap: var(--s3);
}
.nightwatch-shift-row > :first-child { min-width: 0; }
.nightwatch-shift-row > :last-child { justify-self: start; }
.nightwatch-shift-row .btn { width: 100%; padding: 0 var(--s2); }

.nightwatch-shift-time { font-size: var(--text-sm); color: var(--ink-3); }
.nightwatch-shift-member {
  font-size: var(--text-md);
  color: var(--ink);
  white-space: normal;
  overflow-wrap: anywhere;
}

/* The "+" placeholder badge on an open shift is not a unit, so it should not
   carry the unit-badge width. */
.nightwatch-shift-row .nightwatch-unit-badge { min-width: 34px; }

@media (max-width: 420px) {
  .nightwatch-shift-row { grid-template-columns: minmax(0, 1fr) 72px; }
}

/* 12. My Info on mobile. Each Yom Tov period wrapped onto three lines, which
      made the page enormous. Name and dates left, both choices inline right. */
.holiday-status-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  flex-wrap: nowrap;
  gap: var(--s3);
}
.holiday-status-options { flex-wrap: nowrap; gap: var(--s1); }

@media (max-width: 600px) {
  .holiday-status-row { padding: var(--s2) var(--s3); gap: var(--s2); }
  .holiday-status-option {
    min-height: 34px;
    min-width: 0;
    padding: 0 var(--s2);
    font-size: var(--text-xs);
  }
  .btn-check:checked + .holiday-status-option { padding: 0 calc(var(--s2) - 1px); }
  .holiday-status-option::before { width: 5px; height: 5px; flex-basis: 5px; }
  .holiday-period-name { font-size: var(--text-sm); }
  .holiday-period-dates { font-size: var(--text-xs); }
}

/* 15. Roster count buttons. Were boxed mono chips that wrapped onto two lines.
      Now the same dot-and-label pill used for status on the home screen. */
.holiday-roster-stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  font-size: var(--text-xs);
}
.holiday-mini-stat {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 28px;
  padding: 0 var(--s2);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--w-normal);
  letter-spacing: 0.004em;
  word-spacing: 0.08em;
  white-space: nowrap;
  color: var(--ink-2);
  background: transparent;
  border: var(--rule);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color var(--t), color var(--t);
}
.holiday-mini-stat::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--state-in);
}
.holiday-mini-stat.out::before { background: var(--state-out); }
.holiday-mini-stat:hover { border-color: var(--ink-3); color: var(--ink); }

/* 16. Status roster header. The count pills overflowed the card horizontally
      on a phone because the header would not wrap. */
.holiday-roster-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s2) var(--s3);
}
.holiday-roster-header > :first-child { min-width: 0; }
.holiday-roster-columns { min-width: 0; }
.holiday-member-row { min-width: 0; }
.holiday-member-name { overflow-wrap: anywhere; white-space: normal; }

@media (max-width: 600px) {
  .roster-toolbar { flex-direction: column; align-items: stretch; gap: var(--s2); }
  .roster-card .card-body { padding: var(--s3) !important; }
}

/* 17. Info rows. Long labels (hospital liaison names, notes) pushed the phone
      number out past the card edge. Two columns, label wraps, number does not. */
.info-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
}
.info-row-main { min-width: 0; white-space: normal; overflow: visible; }
.info-row-label { white-space: normal; overflow-wrap: anywhere; }
.info-row-note { white-space: normal; overflow-wrap: anywhere; }
.info-call,
.info-row > a,
.info-row > .info-call { margin-left: 0; justify-self: end; white-space: nowrap; }
.info-directory-list { min-width: 0; }

/* 18. Admin. The section heading was space-between with a decorative glyph, so
      every title was shoved to the right-hand edge. */
.admin-settings-heading {
  justify-content: flex-start;
  align-items: baseline;
  gap: var(--s3);
}
.admin-settings-heading > div { min-width: 0; }
.admin-settings-heading-action { margin-left: auto; }
.admin-settings-card { min-width: 0; }

.admin-period-card { min-width: 0; }
.admin-period-dates { gap: var(--s3); }
.admin-period-field,
.admin-season-field { min-width: 0; }
.admin-period-field .form-control,
.admin-season-field .form-control { max-width: 200px; }
.admin-period-top { align-items: flex-start; }

@media (max-width: 600px) {
  .admin-period-dates { flex-direction: column; }
  .admin-period-field .form-control { max-width: none; }
  .status-admin-option { flex-direction: row; gap: var(--s3); padding: var(--s3); }
}

/* Status pill dots. renderHomeStatusItems_ puts the state class on the pill
   itself (`home-status-pill in`), not on a parent, so the descendant rules
   above never matched and every dot stayed grey. */
.home-status-pill::before,
.home-open-pill::before,
.info-als-pill::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--state-off);
}
.home-status-pill.in::before,
.home-status-pill.is-covered::before,
.home-status-pill.is-taken::before { background: var(--state-in); }
.home-status-pill.out::before,
.home-status-pill.is-open::before,
.home-open-pill::before { background: var(--state-out); }
.home-status-pill.unset::before { background: var(--line-strong); }

.home-status-pill.in  { color: var(--state-in); border-color: var(--state-in); }
.home-status-pill.out { color: var(--state-out); border-color: var(--state-out); }
.home-status-pill.unset { color: var(--ink-3); }

/* The pill markup has no inner element, so suppress the seeded/legacy
   .status-icon span where it appears to avoid a double dot. */
.home-status-pill .status-icon,
.home-open-pill .status-icon { display: none; }

/* Long period dates ("September 27-October 2, 2026") were clipped on a phone
   because the mono date is nowrap by default. Let it wrap in narrow rows. */
@media (max-width: 600px) {
  .holiday-status-row .holiday-period-dates,
  .holiday-roster-header .holiday-period-dates {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .holiday-status-row > :first-child { min-width: 0; }
}

/* ==========================================================================
   Second review pass
   ========================================================================== */

/* 1. Home status rows. The date column was 168px, so "September 27-October 2,
      2026" ran under the status pill. Widen it and give the pill its own
      fixed left-aligned column so pills line up down the list. */
.home-current-status-item { grid-template-columns: minmax(0, 1fr) 116px; }
.home-current-status-main { grid-template-columns: minmax(0, 1fr) 232px; }
.home-current-status-date { white-space: nowrap; }

@media (max-width: 900px) {
  .home-current-status-main { grid-template-columns: 1fr; gap: 0; }
  .home-current-status-date { white-space: normal; }
}

/* 8. Status pills on a phone. Fixed 116px was too tight for "Out of town",
      so let the column size to the widest pill and keep the text on one line. */
@media (max-width: 560px) {
  .home-current-status-item { grid-template-columns: minmax(0, 1fr) max-content; }
  .home-status-pill { white-space: nowrap; padding: 3px var(--s2); }
}

/* Tonight's coverage rows use the same two-column shape. */
.home-shift-mini {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content;
  align-items: center;
}
.home-shift-mini > :last-child { justify-self: start; }
.home-open-pill { justify-self: start; white-space: nowrap; }

/* 2. Bulk "All In Town / All Out of Town" carry the same semantic colours as
      the per-period choices instead of Bootstrap success/danger. */
.holiday-bulk-actions .btn-outline-success,
.holiday-bulk-actions .btn-outline-danger {
  --bs-btn-bg: var(--surface);
  --bs-btn-color: var(--ink-2);
  --bs-btn-border-color: var(--line-strong);
  --bs-btn-hover-bg: var(--surface-2);
  --bs-btn-hover-color: var(--ink);
  --bs-btn-active-bg: var(--surface-2);
}
.holiday-bulk-actions .btn-outline-success.active,
.holiday-bulk-actions .btn-outline-success:active {
  --bs-btn-color: var(--state-in);
  --bs-btn-border-color: var(--state-in);
  --bs-btn-active-color: var(--state-in);
  --bs-btn-active-border-color: var(--state-in);
  border-width: 2px;
}
.holiday-bulk-actions .btn-outline-danger.active,
.holiday-bulk-actions .btn-outline-danger:active {
  --bs-btn-color: var(--state-out);
  --bs-btn-border-color: var(--state-out);
  --bs-btn-active-color: var(--state-out);
  --bs-btn-active-border-color: var(--state-out);
  border-width: 2px;
}

/* 3. Code rows. Address, then codes in a fixed left-aligned column, then the
      chevron. The badge column was shrink-to-fit, so codes sat at a different
      x on every row. */
.code-address-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 210px 12px;
  align-items: center;
  gap: var(--s3);
}
.code-address-row > .min-w-0 { min-width: 0; }
.code-badge-row { justify-content: flex-start; flex-wrap: wrap; }
.code-arrow { justify-self: end; }

/* On a phone, long code labels ("5,3,4,2 Clarkson Entrance") made a
   max-content column blow out: the address collapsed to one word per line and
   the second pill was pushed off-screen. Stack instead — address on top,
   codes wrapping beneath. */
@media (max-width: 700px) {
  .code-address-row {
    grid-template-columns: minmax(0, 1fr) 12px;
    grid-template-areas:
      "title arrow"
      "codes codes";
    row-gap: var(--s2);
    column-gap: var(--s2);
    align-items: start;
  }
  .code-address-row > .min-w-0   { grid-area: title; }
  .code-address-row > .code-badge-row { grid-area: codes; }
  .code-address-row > .code-arrow {
    grid-area: arrow;
    align-self: center;
  }
}

/* 5. Nightwatch night card. The heading div was picking up the shared
      card-header rule (flex + hairline + space-between), which is why
      "Current Night / Tonight" sat in its own boxed strip. */
.nightwatch-night { width: 100%; }
.nightwatch-night-head {
  display: block;
  width: 100%;
  margin: 0 0 var(--s3);
  padding: 0 0 var(--s3);
  border-bottom: var(--rule);
}
.nightwatch-night-heading {
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: var(--text-lg);
  font-weight: var(--w-medium);
  color: var(--ink);
}
.nightwatch-night-label { margin-bottom: 2px; }
.nightwatch-night-date { font-size: var(--text-sm); }

.nightwatch-night-shifts {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  width: 100%;
}

/* No left accent rule on shift rows — the state is carried by the badge and
   the action, and the stripe read as decoration. */
.nightwatch-shift-row,
.nightwatch-month-shift-row.nightwatch-shift-row {
  width: 100%;
  border: var(--rule);
  border-left: var(--rule);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.nightwatch-shift-row.is-open,
.nightwatch-shift-row.is-taken,
.nightwatch-shift-row.nightwatch-available,
.nightwatch-shift-row.nightwatch-taken { border-left: var(--rule) !important; }

/* Open vs taken is carried by the badge. */
.nightwatch-shift-row .nightwatch-unit-badge {
  min-width: 40px;
  height: 24px;
  font-size: var(--text-2xs);
}
.nightwatch-shift-row.is-open .nightwatch-unit-badge {
  color: var(--state-out);
  border-color: var(--state-out);
  background: transparent;
}
.nightwatch-shift-row.is-taken .nightwatch-unit-badge {
  color: var(--state-in);
  border-color: var(--state-in);
  background: transparent;
}
.nightwatch-shift-row.is-open .nightwatch-shift-member { color: var(--state-out); }
.nightwatch-shift-row.is-taken .nightwatch-shift-member { color: var(--ink); }

.nightwatch-calendar-shift,
.nightwatch-month-night-card .nightwatch-shift-row { border-left: var(--rule); }

/* 6. Yom Tov schedule editor. The visibility switch sat flush against the date
      inputs, and the remove button was full-height and unsized. */
.admin-period-card { padding: var(--s4); }
.admin-period-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 40px;
  align-items: end;
  gap: var(--s3);
  margin-bottom: var(--s4);
}
.admin-period-remove {
  margin-left: 0;
  justify-self: end;
  width: 40px;
  min-width: 40px;
  min-height: 40px;
  padding: 0;
  font-size: var(--text-lg);
  line-height: 1;
}
.admin-period-dates { margin-bottom: var(--s4); }
.admin-period-visible {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin: 0;
  padding-top: var(--s3);
  border-top: var(--rule);
}

/* 7. Nightwatch counts by unit. Header and body rows were both flex, so the
      five columns never aligned. One shared grid template for both. */
.admin-stats-list { min-width: 0; overflow-x: auto; }
.admin-stats-row,
.admin-stats-head {
  display: grid;
  grid-template-columns: minmax(140px, 2fr) repeat(4, minmax(52px, 1fr));
  align-items: center;
  gap: var(--s2);
  min-height: 40px;
  padding: var(--s1) var(--s2);
  border-bottom: var(--rule);
}
.admin-stats-row > div:not(:first-child),
.admin-stats-head > div:not(:first-child) {
  font-family: var(--font-mono);
  font-feature-settings: "zero" 1;
  text-align: right;
}
.admin-stats-head > div:not(:first-child) {
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
}
.admin-stats-row .admin-stats-unit { text-align: left; overflow-wrap: anywhere; }
.admin-stats-row.is-zero { color: var(--ink-3); }
.admin-stats-row.is-complete .admin-stats-unit { color: var(--state-in); }


/* CAR-1 units. Time in a fixed column, unit flush left beside it, so units
   line up down the night instead of tracking the label width. */
.info-row .carwatch-units,
.info-row .carwatch-open { justify-self: start; }

.carwatch-units { display: flex; flex-wrap: wrap; gap: var(--s2); }

.carwatch-unit {
  display: inline-flex;
  align-items: center;
  min-width: 56px;
  min-height: 26px;
  padding: 0 var(--s2);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-feature-settings: "zero" 1;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--surface-2);
  border: var(--rule);
  border-left: var(--rule);
  border-radius: var(--r-sm);
}

/* The CAR-1 night rows are .info-row, so pin the time column width. */
#carWatchContent .info-row,
.carwatch-night-card .info-row {
  grid-template-columns: 120px minmax(0, 1fr);
  gap: var(--s3);
}
#carWatchContent .info-row-main { min-width: 0; }
#carWatchContent .info-row-label {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-feature-settings: "zero" 1;
  color: var(--ink-3);
  white-space: nowrap;
}

@media (max-width: 480px) {
  #carWatchContent .info-row,
  .carwatch-night-card .info-row { grid-template-columns: 96px minmax(0, 1fr); }
}

/* Home CAR-1 panel rows use the same shape. */
.carwatch-unit { justify-self: start; }


/* Code pills wrap as a group but never break mid-code. */
.code-badge-row { min-width: 0; row-gap: var(--s2); }
.code-pill { white-space: nowrap; max-width: 100%; overflow-wrap: anywhere; }
.code-address-title { overflow-wrap: anywhere; }
.code-address-row { align-items: center; }

/* Home Nightwatch panel: time on the left, unit pills flush left beside it,
   matching the CAR-1 screen and the status rows. */
.home-shift-mini {
  grid-template-columns: 118px minmax(0, 1fr);
  align-items: center;
}
.home-shift-mini > .home-shift-time { white-space: nowrap; }
.home-shift-mini > .carwatch-units,
.home-shift-mini > .home-open-pill { justify-self: start; }

@media (max-width: 480px) {
  .home-shift-mini { grid-template-columns: 96px minmax(0, 1fr); }
}

/* ==========================================================================
   Third review pass
   ========================================================================== */

/* 2. The save toast. showSaveConfirmation_ toggles a `.show` class, but the
      toast had no hidden state, so it appeared the moment it was created and
      never left — it sat on top of the bottom nav until a refresh. */
.app-save-toast {
  z-index: 1100;
  bottom: calc(57px + var(--s4) + env(safe-area-inset-bottom));
  max-width: calc(100% - var(--s6));
  text-align: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(-50%) translateY(var(--s2));
  transition: opacity var(--t), transform var(--t), visibility var(--t);
}
.app-save-toast.show {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* 5. The assign status readout is an empty bordered pill until it has text,
      which rendered as a stray box beside every Assign button. */
.admin-assign-status:empty {
  display: none;
  padding: 0;
  border: 0;
}

/* 6. Nightwatch counts by unit. The columns were 1fr-based, so at phone width
      the header labels collapsed into each other ("SeptemberSeptember").
      Fixed minimums plus a scroll container keeps the table readable. */
.admin-stats-list {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: var(--rule);
  border-radius: var(--r-md);
}
.admin-stats-row,
.admin-stats-head {
  grid-template-columns: minmax(190px, 2fr) repeat(4, 68px);
  min-width: 462px;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
}
.admin-stats-head {
  position: sticky;
  top: 0;
  z-index: 1;
}
.admin-stats-head > div:not(:first-child) {
  line-height: 1.25;
  white-space: normal;
  overflow-wrap: anywhere;
}
.admin-stats-row .admin-stats-unit { white-space: normal; line-height: 1.3; }
.admin-stats-row:last-child,
.admin-stats-list > :last-child { border-bottom: 0; }

/* 4 (layout half). Uncovered-shift rows: the label was fighting the input and
      button for space, so "Sep 2 / Sep 3 · 11-3" broke across three lines. */
.admin-shift-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) 0;
}
.admin-shift-row > :first-child { min-width: 0; }
.admin-shift-title {
  font-size: var(--text-sm);
  font-family: var(--font-mono);
  font-feature-settings: "zero" 1;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.admin-shift-meta { line-height: 1.3; }
.admin-shift-actions {
  display: grid;
  grid-template-columns: 84px auto;
  align-items: center;
  gap: var(--s2);
  margin-left: 0;
}
.admin-shift-actions .admin-unit-input { min-width: 0; padding: var(--s2); }

@media (max-width: 520px) {
  .admin-shift-row { grid-template-columns: 1fr; gap: var(--s2); }
  .admin-shift-actions { grid-template-columns: 84px auto; justify-content: start; }
}

/* The mono unit line is nowrap by default, so a long one ran off the right
   edge of the card. */
.info-member-unit {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* 3. Home Nightwatch rows: pin the pill column so units start at exactly the
      same x on every row regardless of the time string's width. */
.home-shift-mini {
  grid-template-columns: 112px minmax(0, 1fr);
  column-gap: var(--s2);
}
.home-shift-mini > .home-shift-time {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) {
  .home-shift-mini { grid-template-columns: 104px minmax(0, 1fr); }
}

/* ==========================================================================
   Fourth review pass
   ========================================================================== */

/* 6. The Codes heading row stacked on mobile, pushing Sync list onto its own
      line above the search field. Keep it inline with the title. */
.code-directory-header,
#homeView .section-card > .d-flex:first-child {
  display: flex;
  flex-direction: row !important;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}
.codes-sync-btn { flex: 0 0 auto; align-self: center !important; }

/* 5. Member Directory: unit, then name, then number. */
.info-member-row {
  grid-template-columns: 58px minmax(0, 1fr) auto;
  gap: var(--s3);
  align-items: center;
}
.info-member-row .info-member-unit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 24px;
  padding: 0 var(--s1);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-feature-settings: "zero" 1;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--surface-2);
  border: var(--rule);
  border-radius: var(--r-sm);
  margin-left: 0;
  white-space: nowrap;
}
.info-member-row .info-row-label { display: flex; align-items: center; gap: var(--s2); }
.info-member-row .info-call { justify-self: end; }

@media (max-width: 420px) {
  .info-member-row { grid-template-columns: 52px minmax(0, 1fr) auto; gap: var(--s2); }
  .info-member-row .info-call { font-size: var(--text-sm); }
}

/* 7. The Shabbos note is Hebrew — render it right-to-left so it reads
      correctly rather than inheriting the page direction. */
.nightwatch-shabbos-note {
  direction: rtl;
  text-align: right;
  font-size: var(--text-md);
  color: var(--ink-2);
  word-spacing: normal;
}

/* 1. Home shift rows carry either a unit pill plus a name, or an Open pill.
      Both sit in the same fixed second column so they line up. */
.home-shift-mini > .carwatch-units {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}
.home-shift-mini .home-shift-person {
  font-size: var(--text-sm);
  color: var(--ink-2);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* .carwatch-units wraps by design on the CAR-1 screen (several units per
   shift), but in the home row it holds one unit plus a name and must stay
   on a single line. */
/* Explicit column flow rather than relying on flex-wrap, so the unit pill and
   the member name always sit side by side on one line. */
.home-shift-mini > .carwatch-units {
  display: grid !important;
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  justify-content: start;
  align-items: center;
  flex-wrap: nowrap;
}

/* ==========================================================================
   Fifth review pass
   ========================================================================== */

/* 1. Code legend: right-aligned above the list on desktop, centred on mobile. */
.code-legend {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s2);
  /* This is a <p>, so the base `p { max-width: 68ch }` was capping it at
     748px and flex-end aligned to that instead of the list's right edge. */
  max-width: none;
  width: 100%;
  margin: 0 0 var(--s2);
  font-size: var(--text-xs);
  color: var(--ink-3);
}
.code-legend .code-legend-swatch { margin-left: var(--s3); }
.code-legend .code-legend-swatch:first-child { margin-left: 0; }

@media (max-width: 700px) {
  .code-legend { justify-content: center; }
}

/* 3. Mechanical codes read as the "good"/default state, matching the in-town
      pill; electric codes keep the accent so the two stay distinguishable. */
.code-legend-mech { background: var(--state-in); }
.code-legend-elec { background: var(--accent); }

.code-pill-manual {
  color: var(--state-in);
  border-color: var(--state-in);
  background: transparent;
}
.code-pill-auto {
  color: var(--accent);
  border-color: var(--accent);
  background: transparent;
}
.code-pill-empty {
  color: var(--ink-3);
  border-color: var(--line-strong);
  background: transparent;
}

/* 2. Nightwatch home rows: time flush left, unit flush right. */
.home-shift-mini {
  grid-template-columns: minmax(0, 1fr) max-content;
  column-gap: var(--s3);
}
.home-shift-mini > .home-shift-time { justify-self: start; }
.home-shift-mini > .carwatch-units,
.home-shift-mini > .home-open-pill { justify-self: end; }

@media (max-width: 480px) {
  .home-shift-mini { grid-template-columns: minmax(0, 1fr) max-content; }
}

/* CAR-1 night rows follow the same rule: label left, units right. */
#carWatchContent .info-row,
.carwatch-night-card .info-row { grid-template-columns: minmax(0, 1fr) max-content; }
#carWatchContent .info-row > .carwatch-units,
#carWatchContent .info-row > .carwatch-open { justify-self: end; }

/* 1. Text inputs got the generic 2px outline with a 2px offset, which reads as
      a red ring floating on a white gap — very loud on the Codes search field,
      which is focused as soon as the view opens. Inputs signal focus with the
      border plus a soft tint instead. */
.form-control:focus,
.form-control:focus-visible,
.form-select:focus,
.app-search-input:focus,
.app-search-input:focus-visible,
.admin-unit-input:focus,
textarea:focus {
  outline: none;
  outline-offset: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / 0.12);
}

/* --- Unit gate. A status row is meaningless without a unit, so the app asks
       for one before anything else on a fresh device. --------------------- */
.unit-gate {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s4);
  background: rgb(var(--ink-rgb) / 0.45);
}
.unit-gate[hidden] { display: none; }

.unit-gate-panel {
  width: 100%;
  max-width: 380px;
  padding: var(--s5);
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-md);
}
.unit-gate-title {
  font-size: var(--text-xl);
  margin-bottom: var(--s2);
}
.unit-gate-copy {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin-bottom: var(--s4);
}

/* Nothing behind the gate should be reachable by keyboard or scroll. */
body.unit-gate-open { overflow: hidden; }

/* --- Nightwatch -> CAR-1 pickup link. --------------------------------- */
.nightwatch-pickup-link {
  margin: var(--s3) 0 0;
  font-size: var(--text-md);
}
.nightwatch-pickup-link a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Status choices are inert until a unit is set. The gate normally prevents
   reaching this state, but a status row without a unit is meaningless, so the
   controls are disabled rather than merely discouraged. */
body.no-unit-set .holiday-status-options,
body.no-unit-set .status-choice-grid,
body.no-unit-set .holiday-bulk-actions {
  pointer-events: none;
  opacity: 0.45;
}

/* The unit-setup panel is shared: it lives on Home and is borrowed by the
   gate, so it must sit flush in both containers. */
#unitGateSlot .unit-setup-panel,
#shabbosUnitSetupHome .unit-setup-panel {
  margin-bottom: 0 !important;
  padding: 0;
  background: none;
  border: 0;
}
#unitGateSlot .unit-match-list { max-height: 240px; overflow-y: auto; }
.unit-gate-panel { max-height: calc(100vh - var(--s6)); overflow-y: auto; }

/* Hide the "Your unit" panel once a unit is set; Your Status shows it then. */
body:not(.no-unit-set) #homeUnitPanel { display: none; }

/* CAR-1 toolbar: Pickup Shift and Refresh side by side above the coverage. */
.carwatch-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s2);
  flex-wrap: wrap;
}
