/* App components: auth, PIN pad, User Mode home, Caregiver dashboard, and the
 * six feature modules. All colours/radii/type reference tokens.css (the
 * Stitch "Serene Path" palette, docs/design.md §6 pass 2) — no literals here.
 * RTL throughout — logical properties only.
 */

#main {
  /* The gutter, plus the device's safe area on each edge (tokens.css) so
     nothing sits under a notch or the home indicator. Named so a full-bleed
     screen (.aac-board) and a full-height one (.auth-screen, .schedule) can
     cancel or subtract exactly what #main really adds. */
  --main-pad: var(--space-4);
  --main-pad-top: calc(var(--main-pad) + var(--safe-top));
  --main-pad-bottom: calc(var(--main-pad) + var(--safe-bottom));
  /* One centred 40rem column for every screen and device — the owner
     preferred it on tablets and computers over the full-width child screens
     and two-column dashboard tried on 2026-09-29 (reverted the same day).
     Wide caregiver screens (.reports-wide, .operator, …) override it below. */
  max-inline-size: 40rem;
  margin-inline: auto;
  padding-block: var(--main-pad-top) var(--main-pad-bottom);
  /* env() insets are physical and the app is RTL-only: inline-start is the
     right edge, inline-end the left. */
  padding-inline-start: calc(var(--main-pad) + var(--safe-right));
  padding-inline-end: calc(var(--main-pad) + var(--safe-left));
}
/* Every field in a caregiver screen meets the 44px floor (several editor
   inputs/selects were 26–33px tall) and never outgrows its row: a text
   input's intrinsic ~20-character width, or a select's longest option, is
   wider than a phone's card at a large text size. The percentage max makes
   it shrinkable; min 0 lets a flex row shrink it once it wraps to its own
   line. :where() keeps this at zero specificity, so any component's own
   sizing (.field-inline's min 200px, …) still wins. Scoped to #main so a
   child-facing dialog (data-mode="user") keeps base.css's 60px. */
:where([data-mode="caregiver"] #main)
  :where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"], [type="hidden"]), select) {
  min-block-size: var(--touch-min-caregiver);
  min-inline-size: 0;
  max-inline-size: 100%;
}

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-block-end: var(--space-4);
  box-shadow: var(--shadow-1);
}

/* Sign-in/up (original work — no reference art from either export, so this
   stays conservative: the existing type/colour system, nothing invented). */
.auth-screen {
  display: grid;
  place-items: center;
  /* #main's own block padding (gutter + safe areas); subtract it so the
     screen fills the viewport without overflowing it (see the AAC board
     100dvh-vs-#main-padding lesson). */
  min-block-size: calc(100dvh - var(--main-pad-top) - var(--main-pad-bottom));
}
.auth-card {
  inline-size: 100%;
  max-inline-size: 25rem;
  margin-inline: auto; /* was missing — the card hugged the RTL inline-start
                           edge on any viewport wider than #main's 640px cap */
}
.auth-card h1 {
  font-size: var(--text-2xl);
  color: var(--color-primary);
  margin-block-end: var(--space-1);
}
/* The 3 pickable plans, shown above the signup form (views/auth.js) as radio
   rows — no live billing yet, so picking a paid one just skips straight to
   applying it (see plan-payment-note below), no real checkout. */
.plan-preview {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-block-end: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.plan-preview-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--text-sm);
}
.plan-pick-row {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-2);
  cursor: pointer;
}
.plan-pick-row input[type="radio"] {
  margin-block-start: 3px;
  flex: none;
}
.plan-payment-note {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-primary) 10%, var(--color-surface-sunken));
  font-size: var(--text-sm);
}
.plan-payment-note:empty {
  display: none;
}
/* A link that reads as part of a sentence (the "read the full terms" link
   inside the terms checkbox's own <label>) instead of a bordered chip. */
.inline-link {
  display: inline;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: underline;
  cursor: pointer;
}
/* Six digits read as digits, not as prose — centred, tracked, tabular. The
   input carries dir="ltr" so the code doesn't reorder; the page stays RTL. */
.field input.otp-input {
  text-align: center;
  letter-spacing: 0.4em;
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xl);
}

h1,
h2,
h3 {
  font-weight: var(--font-weight-heading);
}
h1 {
  font-size: var(--text-xl);
  margin-block-end: var(--space-3);
}
h2 {
  font-size: var(--text-lg);
  margin-block: var(--space-6) var(--space-3);
}
h3 {
  font-size: var(--text-lg);
  margin-block-end: var(--space-3);
}
.muted {
  color: var(--color-text-muted);
}
.err {
  /* Base --color-danger is only 3.5:1 on light surfaces (fails 4.5:1 for
     body text) — the darker -ink variant is for text, base is for fills. */
  color: var(--color-danger-ink);
  min-block-size: 1.2em;
  margin-block-start: var(--space-2);
}
hr {
  border: none;
  border-block-start: 1px solid var(--color-border);
  margin-block: var(--space-4);
}

/* Forms */
.field {
  margin-block-end: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.field input,
.field select {
  padding: var(--space-3);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
}
/* The invite-signup screen's locked email field (views/auth.js) — reads as
   fixed, not just disabled-looking, since the value still submits. */
.field input[readonly] {
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
}
/* A single-line "email + submit" form — the family-invite box
   (views/dashboard.js's familySection) — not a whole .field's own
   label/margin, just an input and a button side by side. */
.field-inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
.field-inline input {
  flex: 1;
  /* min(), not a bare 200px: on a 320px phone the card's content box is
     narrower than 200px, and the input would push the page sideways. */
  min-inline-size: min(200px, 100%);
  padding: var(--space-3);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
}
.field-inline .err {
  flex-basis: 100%;
}
.checkbox {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-block-end: var(--space-4);
  line-height: 1.4;
}
.checkbox input {
  margin-block-start: 0.2em;
  inline-size: 1.2rem;
  block-size: 1.2rem;
  flex: none;
}

/* Buttons */
.btn-primary {
  display: block;
  inline-size: 100%;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-primary-contrast);
  background: var(--color-primary);
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  margin-block-start: var(--space-2);
}
.btn-primary:disabled {
  opacity: 0.6;
  cursor: progress;
}
/* A quiet bordered chip, not underlined text — docs/design.md §3 permits
   either for .btn-link ("underline or subtle border"); this is the border
   variant, applied everywhere so every back/cancel/action link reads as a
   pressable control. --color-primary on --color-surface and
   --color-border-strong on --color-surface are both already-verified pairs
   (docs/accessibility.md) — reused, not new combinations. */
.btn-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-primary);
  cursor: pointer;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-base);
  font-weight: 600;
  transition: background 120ms ease, transform 120ms ease;
}
.btn-link:hover {
  background: var(--color-surface-sunken);
}
.btn-link:active {
  transform: scale(0.97);
}
.btn-link:disabled {
  opacity: 0.6;
  cursor: progress;
}
.btn-link.danger {
  /* Same outline-chip pattern already used for .queue-badge. */
  color: var(--color-danger-ink);
  border-color: var(--color-danger);
}
.btn-primary.danger {
  /* Base --color-danger can't clear 4.5:1 with white (or dark) text at body
     size — same reasoning as .toast-error. -ink holds 6.45:1 with white. */
  background: var(--color-danger-ink);
}
.btn-primary.danger:hover {
  filter: brightness(1.15);
}

/* Two persistent live regions (ui.js initToasts) hold the toasts; they stack
   upwards from the bottom. Errors stay until their ✕ is pressed. */
.toast-stack {
  position: fixed;
  /* Clear of the home indicator, and of the on-screen keyboard where the
     browser draws it over the page (keyboard.js). */
  inset-block-end: calc(var(--space-6) + var(--safe-bottom) + var(--kb-inset));
  inset-inline: var(--space-4);
  margin-inline: auto;
  max-inline-size: 27.5rem;
  z-index: 1000;
  pointer-events: none;
}
.toast-region {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.toast-region:not(:empty) + .toast-region:not(:empty) {
  margin-block-start: var(--space-2);
}
.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  pointer-events: auto;
  background: var(--color-text);
  color: var(--color-bg);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  text-align: center;
  box-shadow: var(--shadow-2);
}
.toast > span {
  flex: 1;
}
.toast-close {
  flex: none;
  min-inline-size: 44px;
  min-block-size: 44px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: inherit;
  font-size: var(--text-lg);
  cursor: pointer;
}
.toast-error {
  /* White-on-base-danger is 3.5:1 (fails 4.5:1 for body text) in light mode.
     Ink-on-surface holds >= 6.4:1 in both themes. */
  background: var(--color-surface);
  color: var(--color-danger-ink);
  border: 2px solid var(--color-danger);
}

/* Dialogs — replaces native confirm()/prompt(); frontend/js/dialog.js.
   Real <dialog>: showModal() gives the focus trap and Esc-close for free. */
.dialog {
  max-inline-size: 30rem;
  inline-size: calc(100vw - var(--space-8));
  padding: var(--space-6);
  margin: auto; /* centers a modal <dialog>, both axes */
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  border: none;
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-2);
  /* At a large text size (the accessibility menu, or browser zoom) the
     content outgrows the screen: scroll the dialog, never squeeze its
     children — as flex items they'd shrink and overlap each other. */
  max-block-size: calc(100dvh - var(--space-8));
  overflow-y: auto;
}
.dialog > * {
  flex-shrink: 0;
}
.dialog::backdrop {
  /* A plain scrim, not backdrop-filter — no glassmorphism (docs/design.md §3). */
  background: color-mix(in srgb, var(--color-text) 45%, transparent);
}
.dialog-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.dialog-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 40px;
  block-size: 40px;
  flex: none;
  border-radius: 50%;
  background: var(--color-surface-sunken);
  color: var(--color-primary);
}
.dialog.destructive .dialog-icon {
  background: color-mix(in srgb, var(--color-danger) 20%, var(--color-surface-sunken));
  color: var(--color-danger-ink);
}
.dialog-head h2 {
  margin: 0;
  font-size: var(--text-lg);
}
.dialog-body {
  margin: 0;
  color: var(--color-text-muted);
}
.dialog-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
  margin: 0;
}
/* The redeem-reward confirm (rules/index.js) is the one child-facing dialog —
   data-mode="user" pulls in the app-wide 60px floor from base.css. */
[data-mode="user"].dialog .dialog-actions {
  flex-wrap: wrap;
}
/* AAC-board preview (aac/editor.js) — a near-full-screen variant so the
   caregiver sees the board at close to its real on-device size, not a
   phone-sized modal. */
.dialog-preview {
  max-inline-size: 56.25rem;
  inline-size: calc(100vw - var(--space-8));
  /* dvh, not vh: on a phone 100vh is the height with the address bar
     hidden, so the dialog's bottom (and its buttons) ran off-screen. */
  block-size: calc(100dvh - var(--space-8));
  padding: var(--space-4);
}
.preview-body {
  display: flex;
  flex: 1;
  min-block-size: 0;
}
/* The signup screen's "read the full terms" dialog (dialog.js's textDialog)
   — long static content in the same near-full-screen shell as the AAC-board
   preview, scrolling internally instead of growing the dialog. */
.dialog-text-body {
  flex: 1;
  min-block-size: 0;
  overflow-y: auto;
  line-height: 1.6;
}
.dialog-text-body h3 {
  margin-block: var(--space-4) var(--space-2);
  font-size: var(--text-base);
}
.dialog-text-body h3:first-child {
  margin-block-start: 0;
}
.dialog-text-body p,
.dialog-text-body ul {
  margin-block: 0 var(--space-3);
  color: var(--color-text-muted);
}
.dialog-text-body .legal-draft-banner {
  margin-block-end: var(--space-4);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-danger) 12%, var(--color-surface-sunken));
  color: var(--color-danger-ink);
  font-weight: 600;
}
/* The schedule's "where to go" popup (link-chooser.js via
   dialog.js's tileChoiceDialog) — same .tile/.tile-medallion language as the
   home screen's module tiles, just laid out for a dialog instead of the full
   grid: a form column (tiles, then a close link) rather than the usual
   flex-end row of text buttons. */
.dialog-tiles-form {
  flex-direction: column;
  align-items: stretch;
}
/* .tile-grid's own column rule (further down) must not win here — a dialog
   is narrower than the home screen — hence the doubled class. */
.tile-grid.dialog-tiles {
  grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr));
  gap: var(--space-3);
  margin-block-start: 0;
}
.dialog-tiles .tile {
  min-block-size: 140px;
}
.tile-grid.dialog-tiles.single {
  grid-template-columns: minmax(130px, 200px);
  justify-content: center;
}
.dialog-tiles-form > .btn-link {
  align-self: center;
  margin-block-start: var(--space-2);
}
.aac-board.aac-board-preview {
  flex: 1;
  min-block-size: 0;
  block-size: auto;
  margin: 0;
}

/* In-app camera capture (frontend/js/camera.js) — live preview / captured
   still, swapped in place inside one fixed-aspect frame so the dialog doesn't
   jump size between the two states. No transition here: no motion to guard
   under prefers-reduced-motion in the first place. */
.camera-dialog {
  max-inline-size: 30rem;
}
.camera-frame {
  aspect-ratio: 4 / 3;
  background: var(--color-surface-sunken);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.camera-video,
.camera-shot {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
}

/* Empty / celebration states (T3.13) — shared by any screen that previously
   hand-rolled its own version of one of these. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding-block: var(--space-8);
  color: var(--color-text-muted);
  text-align: center;
}
.empty-state .icon {
  color: var(--color-border-strong);
}
.celebration-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-8);
  text-align: center;
  background: var(--color-primary-soft);
  border-radius: var(--radius-lg);
}
.celebration-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 72px;
  block-size: 72px;
  margin-block-end: var(--space-2);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-primary);
}

/* Offline banner (T3.13) — thin strip, unobtrusive, fixed above everything
   including the skip link's focus position. */
.offline-banner {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* The strip's own background fills the notch area; the text starts below. */
  padding-block: calc(var(--space-1) + var(--safe-top)) var(--space-1);
  font-size: var(--text-sm);
  background: var(--color-surface-sunken);
  /* text-muted here is a hairline 4.50:1 at this font size — too close to the
     4.5:1 floor to trust. Full text colour clears it with real margin. */
  color: var(--color-text);
  transform: translateY(-100%);
  transition: transform 200ms ease;
}
.offline-banner.visible {
  transform: translateY(0);
}

/* Global loading indicator — one always-mounted pill (ui.js's
   initLoadingIndicator(), called from app.js next to initOfflineBanner) that
   fades in when any api.js request has been in flight for more than 2s.
   Informs only: pointer-events:none, no scrim, nothing disabled or dimmed.
   Top inline-end (visually top-left in RTL) is the one free corner — the
   bottom belongs to .toast and to child-setup's .setup-bar, and User Mode's
   .lock-btn / .caregiver-entry sit at the inline-start corner. z-index one
   above .offline-banner so the opaque pill stays readable in the (all but
   unreachable — an offline fetch rejects long before 2s) case of both at once.
   Hidden with opacity, never display/visibility: the element must stay in the
   accessibility tree for role="status" to announce the text ui.js writes into
   it. No prefers-reduced-motion block needed — base.css's global kill switch
   neutralizes the transition, and .spinner already has its own override, which
   is also why the pill carries text and not just a ring. */
.loading-indicator {
  position: fixed;
  inset-block-start: calc(var(--space-3) + var(--safe-top));
  /* inline-end is the left edge in this RTL-only app */
  inset-inline-end: calc(var(--space-3) + var(--safe-left));
  z-index: 101;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--text-sm);
  box-shadow: var(--shadow-1);
  pointer-events: none;
  opacity: 0;
  transform: translateY(-6px);
  transition:
    opacity 200ms ease,
    transform 200ms ease;
}
.loading-indicator.visible {
  opacity: 1;
  transform: translateY(0);
}
/* Don't tick an infinite rotation for the life of the app on a kiosk tablet
   just because the element is permanently in the DOM. */
.loading-indicator:not(.visible) .spinner {
  animation-play-state: paused;
}

/* Boot screen (T3.3) — mount() already stripped #main's own .boot centering
   utility (base.css) by the time this renders, so it centers itself. */
.boot-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-8);
  min-block-size: 100dvh;
  justify-content: center;
  padding: var(--space-6);
  text-align: center;
}
.boot-wordmark {
  font-size: var(--text-2xl);
  color: var(--color-primary);
}
.boot-states {
  position: relative;
  inline-size: 100%;
  max-inline-size: 20rem;
  min-block-size: 80px;
}
.boot-state {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 300ms ease;
}
.boot-state.active {
  opacity: 1;
  pointer-events: auto;
}
.spinner {
  inline-size: 32px;
  block-size: 32px;
  border: 3px solid var(--color-border);
  border-block-start-color: var(--color-primary);
  border-radius: 50%;
  animation: spin 900ms linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
    border-block-start-color: var(--color-border); /* a static ring, not a frozen mid-spin frame */
  }
}
:root[data-a11y-motion] .spinner {
  animation: none;
  border-block-start-color: var(--color-border);
}
/* Inline variant for a busy button (ui.js's withBusy()) — same ring, sized to
   sit next to a button label instead of filling a boot screen. */
.spinner-sm {
  inline-size: 18px;
  block-size: 18px;
  border-width: 2px;
  vertical-align: middle;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* PIN pad */
.pin-card {
  text-align: center;
  max-inline-size: 22.5rem;
  margin-inline: auto;
}
.pin-dots {
  /* A code fills left-to-right, like the keypad under it (not RTL). */
  direction: ltr;
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  margin-block: var(--space-6);
}
.dot {
  inline-size: 1rem;
  block-size: 1rem;
  border-radius: 50%;
  border: 2px solid var(--color-primary);
}
.dot.filled {
  background: var(--color-primary);
}
.pin-confirm {
  margin-block-start: var(--space-3);
  inline-size: 100%;
}
.pin-keys {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
  /* A numeric keypad reads 1-2-3 left-to-right even in an RTL UI. */
  direction: ltr;
}
.pin-key {
  min-block-size: 64px;
  font-size: var(--text-lg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill); /* docs/design/stitch-export DESIGN.md: "Keypads: … perfectly circular or high roundedness" */
  background: var(--color-bg);
  cursor: pointer;
}
.pin-key.subtle {
  color: var(--color-text-muted);
  font-size: var(--text-base);
}

/* User Mode home */
.home {
  position: relative;
  padding-block-start: var(--space-8);
}
.lock-btn {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  font-size: 1.4rem;
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--space-2);
}
/* Home header row: greeting on one side, the caregiver-mode entry clearly
   separated on the other. The child-switcher chips used to sit here too; they
   moved to the Caregiver Mode dashboard (.active-child) so the child can't
   change profiles on the locked tablet. */
.home-head {
  display: flex;
  flex-wrap: wrap; /* greeting over the button at a large text size */
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.home-head h1 {
  margin: 0;
}
.caregiver-entry {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  min-block-size: var(--touch-min);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  color: var(--color-text);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-1);
}
.caregiver-entry:active {
  transform: scale(0.97);
}
/* As many tiles per row as fit: three on a portrait tablet, more on a
   landscape one or a desktop. rem, not px, so a bigger text size (the
   accessibility menu) makes fewer, wider tiles instead of clipped labels;
   min(…, 100%) keeps one tile from ever being wider than the screen. */
.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(12rem, 100%), 1fr));
  gap: var(--space-4);
  margin-block-start: var(--space-6);
}
/* On a phone 12rem would leave one tile per row; 9rem keeps two at the
   normal text size (and still drops to one at 200%). */
@media (max-width: 600px) {
  .tile-grid {
    grid-template-columns: repeat(auto-fill, minmax(min(9rem, 100%), 1fr));
  }
}
.tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-block-size: 200px;
  padding: var(--space-4);
  font-size: var(--text-xl);
  font-weight: 600;
  border: none;
  /* The biggest kiosk-level radius — docs/design.md's "Large tiles and
     modals in User Mode use the largest radius" — this is the app's most
     prominent navigation surface. */
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-1);
  cursor: pointer;
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.tile:active {
  transform: scale(0.96);
  box-shadow: none;
}
/* A colour-tinted circle housing the icon, sized up for the home screen's
   bigger, more prominent tiles. Secondary, not primary, keeping
   --color-primary sparse (docs/design.md §3 "one accent"). */
.tile-medallion {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 80px;
  block-size: 80px;
  border-radius: 50%;
  background: var(--color-secondary-soft);
  color: var(--color-secondary);
}
.child-switch,
/* A person's modules as a grid of cards (views/dashboard.js moduleCard):
   the switch, a lock/trial note, and "עריכה" while the module is on. */
.module-cards {
  display: grid;
  /* The dashboard is a ~600px column on a computer: 3 cards a row there. */
  grid-template-columns: repeat(auto-fill, minmax(min(10rem, 100%), 1fr));
  gap: var(--space-2);
  margin-block: var(--space-3);
}
@media (max-width: 600px) {
  .module-cards {
    grid-template-columns: repeat(auto-fill, minmax(min(9.5rem, 100%), 1fr));
  }
}
.module-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.module-card .toggle {
  inline-size: 100%;
  justify-content: space-between;
  font-weight: 600;
  line-height: 1.25;
}
.module-card-note {
  font-size: var(--text-sm);
}
.module-card-edit {
  margin-block-start: auto;
  min-block-size: var(--touch-min-caregiver);
}
.module-card.off {
  background: var(--color-bg);
}
.module-card.off .toggle {
  color: var(--color-text-muted);
  font-weight: 400;
}
.module-card.off .module-card-edit {
  display: none;
}
.toggle-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.child-switch {
  margin-block-start: var(--space-4);
  margin-block-end: var(--space-4);
}
/* Active-profile switcher at the top of the Caregiver Mode dashboard. */
.active-child {
  margin-block: var(--space-4);
}
.active-child p {
  margin-block-end: var(--space-2);
}
.active-child .child-switch {
  margin-block: 0;
}
/* …arranged in blocks ("הילדים שלי", then each organization) with the unit
   filter and a small title per unit (dashboard.js::activeChildSwitcher). */
.active-child-block + .active-child-block {
  margin-block-start: var(--space-4);
}
.active-child-title {
  margin-block: 0 var(--space-2);
  font-size: var(--text-base);
}
.active-child .unit-filter {
  margin-block: 0 var(--space-3);
}
.active-child .unit-heading {
  margin-block: var(--space-3) var(--space-1);
  font-size: var(--text-sm);
}
.active-child .active-now {
  margin-block: var(--space-2) 0;
}
/* "מוצג: <unit> בלבד. הצגת הכל" above the org's management areas. */
.unit-focus-note {
  margin-block: 0 var(--space-3);
}
.chip {
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-bg);
  cursor: pointer;
  font-size: var(--text-base);
}
.chip.active {
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-color: var(--color-primary);
}

.dash-head-actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.dash-whoami {
  margin-block: 0 var(--space-3);
}
.staff-form > * + * {
  margin-block-start: var(--space-2);
}
.staff-form .field-inline select {
  min-inline-size: min(160px, 100%);
}
.checkbox.inline {
  display: inline-flex;
  margin-inline-end: var(--space-3);
}

/* Organization tier: the client list grouped by unit (כיתה / סדנה / בית),
   the filter chips above it, and the unit badge on a client card. */
.unit-filter {
  margin-block: var(--space-2) var(--space-4);
}
.unit-heading {
  margin-block: var(--space-4) var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-base);
}
.unit-badge {
  margin-inline-start: auto;
  font-size: var(--text-sm);
}
.unit-move {
  margin-block-end: var(--space-2);
}
.unit-move select {
  flex: 1;
  min-inline-size: min(160px, 100%);
}
.unit-card-row {
  flex-wrap: wrap;
}
.unit-rows .unit-row {
  margin-block-end: var(--space-2);
}

/* Dashboard */
.dash-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
}
.child-card-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
/* A small colour-tinted circle — the same language as .tile-medallion. */
.child-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 40px;
  block-size: 40px;
  flex: none;
  border-radius: 50%;
  background: var(--color-secondary-soft);
  color: var(--color-secondary);
  font-size: var(--text-lg);
  font-weight: 700;
}
.child-card-head h3 {
  margin: 0;
}
.child-card .toggle-list {
  flex-direction: column;
  gap: var(--space-3);
  margin-block: var(--space-3);
}
.toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-base);
  /* The whole label is the tap target (it toggles its switch), so it is the
     label that meets the caregiver floor, not the 26px-tall switch. */
  min-block-size: var(--touch-min-caregiver);
  cursor: pointer;
}
/* A module's toggle + its plan-lock link (dashboard.js's moduleLockBadge),
   side by side with the link pushed to the far end. */
.toggle-row {
  display: flex;
  flex-wrap: wrap; /* a long label + the lock link on a 320px phone */
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
/* Real track+thumb switch (docs/design.md §3 "toggle row — label + switch"),
   drawn entirely on the native <input> — ::before/::after don't render on a
   replaced element like <input>, so a thumb "element" has to be a background
   image, not a pseudo-element. Stays a real, fully keyboard/AT-operable
   checkbox; only its paint changes. */
.toggle input {
  appearance: none;
  -webkit-appearance: none;
  inline-size: 44px;
  block-size: 26px;
  margin: 0;
  border: none;
  border-radius: var(--radius-pill);
  background-color: var(--color-border-strong);
  background-image: radial-gradient(circle, var(--color-surface) 9px, transparent 9.5px);
  background-repeat: no-repeat;
  /* background-position has no logical (inline-start/end) form — this is a
     deliberate physical exception, not an RTL slip: off sits at the reading
     start (right), :checked slides the thumb to the end (left). */
  background-position: right 4px center;
  flex: none;
  cursor: pointer;
  transition: background-color 150ms ease, background-position 150ms ease;
}
.toggle input:checked {
  background-color: var(--color-secondary);
  background-position: left 4px center;
}
.toggle input:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------ AAC board */

.aac-board {
  /* The viewport minus the safe areas — #main's padding already holds those
     (--main-pad-top/-bottom), so a full 100dvh would scroll by the notch +
     home-indicator height on an iPhone. The margin cancels just the gutter
     part of #main's padding, so the board reaches the edges of the safe area
     and the page never scrolls, defeating the no-scroll grid-fit below.
     Not needed for the preview variant, which isn't inside #main. */
  block-size: calc(100dvh - var(--safe-top) - var(--safe-bottom));
  margin: calc(-1 * var(--main-pad, var(--space-4)));
  /* A small gutter of its own so edge cards aren't pressed against the
     glass (or a phone's rounded corner). */
  padding: var(--space-2);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
/* Shared User-Mode back+home bar (ui.js's navBar()) — replaces the old
   close-icon-only .aac-topbar as every module screen's persistent header, so
   both controls stay visible above whatever sub-view the module swaps in. */
.nav-bar {
  display: flex;
  /* Only wraps when it doesn't fit — the badges of "קריאה והקלדה" at 200%
     text pushed "בית" off a portrait tablet. */
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.nav-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-block-size: var(--touch-min);
  padding-inline: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-text);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
}
.nav-btn:active {
  transform: scale(0.97);
}
.nav-title {
  flex: 1;
  margin: 0;
  font-size: var(--text-lg);
  text-align: center;
}
/* Shared by every module screen (navBar() in ui.js) — most pass at most one
   extra badge and a short title, which fits at phone width even with two
   min-block-size:60px buttons either side. "קריאה והקלדה" is the one screen
   with a long title *and* two badges, and at ~390px the row's min-content
   width runs well past the viewport with no way to shrink (.nav-title had
   flex:1 but no min-inline-size:0, so it couldn't shrink below its own text).
   Wrapping plus a title that can actually shrink/ellipsize fixes it there and
   costs nothing on every other screen that already fit. */
@media (max-width: 600px) {
  .nav-bar {
    flex-wrap: wrap;
    row-gap: var(--space-2);
  }
  /* Wraps onto a second line rather than ellipsizing — at 200% text an
     ellipsis cut most of the title off (WCAG 1.4.4). */
  .nav-title {
    min-inline-size: 0;
    flex-basis: 100%;
    order: -1;
    font-size: var(--text-base);
    overflow-wrap: anywhere;
  }
}

/* Sentence bar — one horizontal row (docs/design.md §T1.1). The chips scroll
   sideways rather than wrapping to more lines, so the bar's height is fixed and
   the board below never gets pushed off-screen as words pile up. (Only at a
   very large text size do the buttons drop below the chips.) */
.sentence-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  min-block-size: calc(var(--touch-min) + var(--space-2) * 2);
}
.sentence-chips {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--space-2);
  /* The small basis lets the bar wrap (buttons on a line of their own) only
     when they leave the chips almost nothing — at 200% text on a phone the
     three buttons alone are wider than the screen. At the normal size a
     360px phone still keeps one row. */
  flex: 1 1 2.5rem;
  min-inline-size: 0;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}
.sentence-chip {
  flex: none;
  white-space: nowrap;
  background: var(--color-bg);
  font-weight: 600;
}
.sentence-actions {
  display: flex;
  flex-wrap: wrap;
  flex: 0 1 auto;
  gap: var(--space-2);
}
.sb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-block-size: var(--touch-min);
  min-inline-size: var(--touch-min);
  padding-inline: var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  font-size: var(--text-base);
  cursor: pointer;
}
.sb-btn.speak {
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-color: var(--color-primary);
  font-weight: 600;
}
.sb-btn:disabled {
  opacity: 0.4;
}

/* Category tabs */
.cat-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.cat-tab {
  min-block-size: var(--touch-min);
  padding-inline: var(--space-4);
  border: 2px solid var(--cat, var(--color-border-strong));
  border-radius: var(--radius-pill);
  background: var(--color-bg);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
}
.cat-tab.active {
  /* Selection state uses the secondary wash, keeping --color-primary sparse for
     primary actions only (docs/design.md §3 "one accent"; confirmed by the
     export — the active category tab is a secondary-container pill, not
     primary). A caregiver-assigned category colour (--cat) still overrides the
     fill; text stays the dark secondary ink rather than white, since a custom
     --cat is more often a light/pastel pick than a dark one. */
  background: var(--cat, var(--color-secondary-soft));
  color: var(--color-secondary);
  border-color: transparent;
}

/* Segmented variant (docs/design/stitch-export-2/_2/) — a track with the tabs
   inset inside it, rather than free-floating pills. Used where there are
   always exactly two or three fixed tabs filling the width (reading &
   writing) rather than a scrollable category row. */
.cat-tabs.segmented {
  /* Wraps only when the options don't fit (a narrow phone, large text) —
     otherwise the last one was cut off. */
  flex-wrap: wrap;
  gap: var(--space-1);
  padding: var(--space-1);
  background: var(--color-surface-sunken);
  border-radius: var(--radius-pill);
}
.cat-tabs.segmented .cat-tab {
  flex: 1;
  border: none;
  background: none;
}
.cat-tabs.segmented .cat-tab.active {
  background: var(--color-surface);
  box-shadow: var(--shadow-1);
}

/* Breadcrumb — the AAC board's drill-down trail (board.js only). Shown only
   once the child is inside a category: a back button pinned at the start
   (RTL right) plus the path, each level a button back to it. One row that
   scrolls sideways for a deep trail rather than wrapping. */
.aac-breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
}
.crumb-back {
  flex: none;
  padding-inline: var(--space-2);
}
.crumb-trail {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex: 1;
  min-inline-size: 0;
  overflow-x: auto;
  scrollbar-width: thin;
  white-space: nowrap;
}
.crumb {
  flex: none;
  display: inline-flex;
  align-items: center;
  /* The caregiver's board editor uses the same trail; User Mode gets its 60px
     from base.css's [data-mode="user"] button rule. */
  min-block-size: var(--touch-min-caregiver);
  padding: var(--space-1) var(--space-2);
  border: none;
  border-radius: var(--radius-md);
  background: none;
  color: var(--color-secondary);
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
}
.crumb-sep {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--color-text-muted);
}
.crumb-current {
  color: var(--color-text);
  cursor: default;
}

/* Sub-category tile in the child's board (board.js only) — the same picture +
   label shape as a word card, plus a doubled frame in the category colour: a
   ring set inside the border reads as "a box you open", not a word. */
.aac-cat-card {
  position: relative;
  border-width: 3px;
  outline: 2px solid var(--cat, var(--color-border-strong));
  outline-offset: -7px;
}
/* A folder tile also gets a small triangular ribbon in its own colour at the
   top-inline-start corner — a clearer "this opens into more cards" cue than
   the outline ring alone, since otherwise a folder and a word card share the
   same rounded-rectangle silhouette. clip-path draws the wedge relative to
   the pseudo-element's own box, so this is correct in the app's fixed RTL
   layout with no left/right-specific rule needed. */
.aac-cat-card::before {
  content: "";
  position: absolute;
  top: 0;
  inset-inline-start: 0;
  inline-size: 28px;
  block-size: 28px;
  background: var(--cat, var(--color-border-strong));
  clip-path: polygon(0 0, 100% 0, 0 100%);
  border-start-start-radius: var(--radius-lg);
  pointer-events: none;
}

/* Card grid — sized to always fit the viewport with no scrolling: board.js
   measures the grid box and picks --cols/--rows for the active category's
   card count, rather than letting content overflow into a scrollbar (a
   locked kiosk tablet gives a child no way to scroll back). */
.aac-grid {
  display: grid;
  /* --cell-w/--cell-h (board.js's fitToGrid) are the fit calculation clamped
     to a comfortable max size and aspect ratio, so a sparse board (1-2 cards)
     gets tiles sized like any other board instead of stretching to fill the
     screen. justify/align-content centres the resulting (smaller) grid in
     the box rather than pinning it to a corner. */
  grid-template-columns: repeat(var(--cols, 3), var(--cell-w, 1fr));
  grid-template-rows: repeat(var(--rows, 1), var(--cell-h, 1fr));
  justify-content: center;
  align-content: center;
  gap: var(--space-3);
  flex: 1;
  min-block-size: 0;
  overflow: hidden;
}
/* Only reached past ~100 cards in one category on a real tablet (board.js's
   fitGrid comment) — cards would drop under the 60px touch floor to keep
   fitting on one screen, so this scrolls instead as the accessibility floor
   takes priority over the no-scroll preference. */
.aac-grid.aac-grid-scroll {
  overflow-y: auto;
  align-content: start;
}
/* The picture *is* the card — it fills the image area edge-to-edge with the
   Hebrew word on a strip below (docs/design.md §T1.1). A 3px border in the
   card's own category colour ties it to its category. */
.aac-card {
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 0;
  min-block-size: var(--touch-min);
  min-inline-size: var(--touch-min);
  padding: 0;
  overflow: hidden;
  border: 3px solid var(--cat, var(--color-border-strong));
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-1);
  cursor: pointer;
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.aac-card:active {
  transform: scale(0.96);
  box-shadow: none;
}
/* Text-only card (no symbol/photo): the word is the whole card, large. */
.aac-card-text {
  grid-template-rows: 1fr;
  place-items: center;
  padding: var(--space-3);
}
.aac-card-text .card-label {
  /* No image area competing for room, so a bigger share of the tile. */
  font-size: clamp(1rem, calc(var(--cell-h, 200px) * 0.18), 2rem);
  border: none;
}
.card-image {
  display: flex;
  align-items: center;
  justify-content: center;
  min-block-size: 0;
  padding: var(--space-2);
  background: color-mix(
    in srgb,
    var(--cat, var(--color-secondary-soft)) 14%,
    var(--color-surface)
  );
}
.card-visual {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
}
.card-visual-text {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 100%;
  block-size: 100%;
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--color-secondary);
}
.card-label {
  padding: var(--space-2);
  /* Scales with the tile (board.js's --cell-h) instead of a size fixed
     regardless of card size — a capped, small tile keeps a readable word
     instead of the word looking lost under a shrunken picture area. */
  font-size: clamp(0.85rem, calc(var(--cell-h, 200px) * 0.13), 1.375rem);
  font-weight: 600;
  text-align: center;
  line-height: 1.15;
  border-block-start: 1px solid var(--color-border);
  background: var(--color-surface);
}

/* AAC board drag-to-arrange ("סידור הלוח", aac/editor.js's openArrange →
   board.js's `arrange` mode → arrange.js). Runs inside the same near-full-
   screen dialog as the read-only preview (.dialog-preview / .aac-board-
   preview above) — this just adds the hint line, a floating drag ghost, drop
   highlights and a trash bin on top of the real board. */
.aac-arrange-hint {
  margin: 0;
  padding-inline: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  text-align: center;
}
/* A tile mid-drag stays in the grid (so the layout doesn't reflow under the
   user's finger) but goes fully transparent, reading as an open gap — the
   other same-kind tiles live-shift into place around it (arrange.js's
   updatePreview) and the floating ghost below is the thing actually tracking
   the pointer, so there is nothing left to show at the tile's own slot. */
.aac-tile-dragging {
  opacity: 0;
}
/* The floating clone that follows the pointer. Position is set inline
   (arrange.js) on every move; only the fixed look lives here. touch-action
   isn't needed — pointer-events:none takes it out of hit-testing and gesture
   handling entirely. */
.aac-drag-ghost {
  position: fixed;
  z-index: 500;
  pointer-events: none;
  box-shadow: var(--shadow-2);
  transform: scale(1.04);
}
/* HTML5 drag-and-drop doesn't fire on touch, so arrange.js drives this
   entirely off Pointer Events — but a tile still needs touch-action:none or
   the browser starts panning the page instead of letting a touch drag start.
   Scoped to the tile itself (not the whole grid): a press on the gap between
   tiles still scrolls normally on a board too large to fit on one screen (in
   practice `.aac-grid` itself never scrolls — it's `overflow: hidden` by
   design, see board.js's fitToGrid — except the rare `.aac-grid-scroll`
   fallback past ~100 cards in one category, where the gaps still scroll).
   user-select/-webkit-touch-callout stop iOS's image/text callout and
   Android's text selection from firing during the ~500ms pickup hold — both
   would otherwise cancel the gesture partway through (see arrange.js's
   PICKUP_MS and its `contextmenu` guard for Android's long-press menu). */
.aac-arrange .aac-card {
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
/* Highlight for a card hovering the middle half of a folder tile — the one
   case arrange.js still treats as "drop into", rather than an insert among
   the folders. A live-shift preview (arrange.js's updatePreview) is the
   affordance for every other case, so there's no separate insertion marker
   to draw. */
.aac-drop-into {
  outline: 3px solid var(--color-success);
  outline-offset: 4px;
  background: color-mix(in srgb, var(--color-success) 16%, var(--color-surface));
}
/* Fills in over the same ~700ms the caregiver has to hold a tile over a
   folder before it's entered (arrange.js's HOLD_MS) — a freshly-created
   element each time a hold starts, so the animation always plays from the
   start rather than fighting a class-toggle restart quirk. `.aac-cat-card`
   is already `position: relative` (see above), so this anchors to the tile
   itself. `animation-duration` is set inline to stay in lockstep with the JS
   timer if that constant ever changes. */
.aac-hold-ring {
  position: absolute;
  inset: 6px;
  border-radius: inherit;
  border: 4px solid var(--color-success);
  pointer-events: none;
  clip-path: inset(0 100% 0 0);
  animation-name: aac-hold-fill;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
@keyframes aac-hold-fill {
  to {
    clip-path: inset(0 0 0 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .aac-hold-ring {
    animation: none;
    clip-path: inset(0 0 0 0);
  }
}
:root[data-a11y-motion] .aac-hold-ring {
  animation: none;
  clip-path: inset(0 0 0 0);
}
/* Trash bin — only present in arrange mode, and only visible while a drag is
   in progress (arrange.js toggles .aac-trash-visible), so it never competes
   with the grid the rest of the time. */
.aac-trash {
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
  padding: var(--space-3);
  border: 2px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  color: var(--color-text-muted);
}
.aac-trash.aac-trash-visible {
  display: flex;
}
.aac-trash.aac-drop-hot {
  border-color: var(--color-danger);
  border-style: solid;
  background: color-mix(in srgb, var(--color-danger) 16%, var(--color-surface));
  color: var(--color-danger-ink);
}
@media (prefers-reduced-motion: reduce) {
  .aac-tile-dragging,
  .aac-drag-ghost {
    transition: none;
  }
  /* The live-shift preview (arrange.js's updatePreview) moves other tiles
     with an inline transform riding .aac-card's own transition — kill that
     too, so tiles jump straight to their new slot instead of sliding. */
  .aac-arrange .aac-card {
    transition: none;
  }
}

/* Generic drag-to-reorder for a plain vertical list (frontend/js/drag-reorder.js)
   — currently the schedule editor's task list. Same ghost/dragging shapes as
   the AAC board's arrange-mode equivalents above (.aac-tile-dragging/
   .aac-drag-ghost) but scoped to a row instead of a grid tile; unlike arrange
   mode this is an insert, not a swap, so the drop affordance is an insertion
   line rather than an outline on the row being traded. */
.drag-handle {
  display: inline-flex;
  flex: none;
  color: var(--color-text-muted);
  cursor: grab;
  /* Only the handle opts out of page scrolling and grabs immediately — the
     row body instead needs a long-press hold (drag-reorder.js's PICKUP_MS)
     before it opts out, so a swipe on the row still scrolls the list. */
  touch-action: none;
}
/* Same reasoning as .aac-arrange .aac-card: a long-press pickup on the row
   body (drag-reorder.js) must survive the ~500ms hold without iOS raising
   its text/image callout or Android raising a context menu (see that
   module's `contextmenu` guard). Deliberately no touch-action here — unlike
   the AAC grid, this list can be taller than the screen and must stay
   scrollable from a swipe that never reaches the hold. */
.sched-item-row {
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.row-dragging {
  opacity: 0.35;
}
.drag-ghost {
  position: fixed;
  z-index: 500;
  pointer-events: none;
  box-shadow: var(--shadow-2);
}
/* Insertion line: the dragged row lands *at the line*, it does not trade
   places with the row it's over. An absolutely positioned pseudo-element,
   deliberately — a real border or margin would grow the row and reflow every
   row below it while the finger is mid-drag, so the list would jitter and the
   row under the pointer would change on its own. This adds zero layout. */
.drop-before,
.drop-after {
  position: relative;
}
.drop-before::after,
.drop-after::after {
  content: "";
  position: absolute;
  inset-inline: 0; /* logical, so it spans the row correctly under RTL */
  block-size: 4px;
  border-radius: 2px;
  background: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-surface); /* keeps it legible over the row border */
  pointer-events: none;
  z-index: 1;
}
/* Centred in the list's own gap (--space-2), so it reads as a slot between
   two rows and not as a decoration on one of them. */
.drop-before::after {
  inset-block-start: calc(var(--space-2) / -2 - 2px);
}
.drop-after::after {
  inset-block-end: calc(var(--space-2) / -2 - 2px);
}
@media (forced-colors: active) {
  .drop-before::after,
  .drop-after::after {
    background: Highlight;
  }
}
@media (prefers-reduced-motion: reduce) {
  .row-dragging,
  .drag-ghost {
    transition: none;
  }
}

/* The schedule editor's per-row time picker (editor.js's itemRow) — a native
   <input type="time">, always visible and always editable, not static text.
   flex:none so the row's flex layout (.editor-card-label has flex:1) doesn't
   stretch or crush its intrinsic width. */
.sched-item-time {
  flex: none;
}
/* This row now packs a drag handle + a fixed-width time picker + a label +
   action buttons — on top of the phone-width squeeze already handled for
   .nav-bar above, wrap it rather than let it force horizontal scroll. */
@media (max-width: 600px) {
  .sched-item-row {
    flex-wrap: wrap;
  }
  .sched-item-row .editor-card-actions {
    flex-basis: 100%;
    justify-content: flex-end;
  }
}

/* --------------------------------------------------------------- AAC editor */

.child-card-actions {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* Child-setup wizard bar (frontend/js/views/child-setup.js). Fixed to the
   bottom, appended to <body> — outside #main — so it survives each module
   editor's mount() call. #main gets bottom padding while it's up so the bar
   doesn't cover the editor's last controls. */
.setup-bar {
  position: fixed;
  /* Above the on-screen keyboard where the browser draws it over the page
     (keyboard.js); 0 otherwise. */
  inset-block-end: var(--kb-inset);
  inset-inline: 0;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-3) var(--space-4);
  /* The bar's background runs under the home indicator; its buttons don't. */
  padding-block-end: calc(var(--space-3) + var(--safe-bottom));
  padding-inline: calc(var(--space-4) + var(--safe-right)) calc(var(--space-4) + var(--safe-left));
  background: var(--color-surface);
  border-block-start: 1px solid var(--color-border-strong);
  box-shadow: var(--shadow-2);
}
.setup-bar-info {
  flex: 1;
  min-inline-size: 12rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.setup-bar-title {
  font-weight: 600;
  font-size: var(--text-sm);
}
.setup-bar-track {
  block-size: 6px;
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  overflow: hidden;
}
.setup-bar-fill {
  display: block;
  block-size: 100%;
  inline-size: 0;
  background: var(--color-primary);
  transition: inline-size 200ms ease;
}
.setup-bar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.setup-bar-actions .btn-primary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  inline-size: auto;
  margin-block-start: 0;
  min-block-size: var(--touch-min);
}
.setup-bar-actions .btn-link {
  min-block-size: var(--touch-min);
}
body[data-setup="1"] #main {
  padding-block-end: calc(7rem + var(--safe-bottom));
}
@media (prefers-reduced-motion: reduce) {
  .setup-bar-fill {
    transition: none;
  }
}
.cat-block-head {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  margin-block-end: var(--space-3);
}
.cat-name-input {
  flex: 1;
  padding: var(--space-2);
  font-size: var(--text-base);
  font-weight: 600;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
}
.cat-block-name {
  flex: 1;
  font-size: var(--text-base);
  font-weight: 700;
}
/* Nested category block — a colour edge on the start side marks it as a
   sub-category of the block above it (the margin-inline-start indent is set
   inline by editor.js per depth). */
.cat-block[data-depth] {
  border-inline-start: 3px solid var(--color-secondary-soft);
}
/* Picture control shared by the card form and the category form. */
.visual-editor {
  margin-block: var(--space-2);
}
.card-form .visual-editor .visual-preview {
  margin-block-start: 0;
}
/* Category colour picker (openCategoryForm). One tappable swatch per palette
   colour + an "אוטומטי" chip; the picked one gets a ring. */
.swatch-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block: var(--space-2);
}
.swatch {
  inline-size: var(--touch-min);
  block-size: var(--touch-min);
  border-radius: var(--radius-md);
  background: var(--sw, var(--color-surface-sunken));
  border: 2px solid transparent;
  cursor: pointer;
}
.swatch-auto {
  inline-size: auto;
  padding-inline: var(--space-3);
  font-weight: 600;
  color: var(--color-text);
}
.swatch-on {
  border-color: var(--color-text);
  box-shadow: inset 0 0 0 2px var(--color-surface);
}
.editor-card-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-block-end: var(--space-3);
}
.editor-card-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.editor-card-label {
  flex: 1;
  font-weight: 600;
}
/* Small "linked to a בוא נדבר folder / המשימות שלי checklist" pills on a
   schedule-item row (modules/schedule/editor.js's linkBadges). flex-basis:
   100% drops them onto their own line, under the head/time/handle, instead
   of squeezing .editor-card-actions into a cramped column when the row is
   too narrow for everything on one line. */
.editor-badges {
  display: flex;
  gap: var(--space-2);
  flex: 1 0 100%;
  order: 10;
  padding-inline-start: calc(20px + var(--space-3));
}
.editor-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  white-space: nowrap;
}
/* The כרטיסיה + name as one tap target (ui.js's editableCardHead) — a plain
   button reset to sit inline with the rest of an .editor-card-row. */
.editor-card-head {
  display: flex;
  flex: 1;
  align-items: center;
  gap: var(--space-3);
  min-block-size: 44px;
  padding: var(--space-2);
  margin-inline-start: calc(var(--space-2) * -1);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  font: inherit;
  color: inherit;
  text-align: start;
  cursor: pointer;
}
.editor-card-head:hover,
.editor-card-head:focus-visible {
  background: var(--color-surface);
}
.editor-card-head .editor-card-label {
  flex: 1;
}
.editor-card-actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
}
.editor-thumb {
  inline-size: 40px;
  block-size: 40px;
  object-fit: contain;
  flex: none;
}
.editor-thumb-text {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--color-text-muted);
  background: var(--color-surface);
  border-radius: var(--radius-sm);
}

/* Visual picker preview — shared by the card form and every other editor that
   attaches a picture (schedule / My Tasks / rules / rewards). Was scoped to
   .card-form only; those forms aren't .card-form, so without this a photo
   rendered at full intrinsic size and blew the form apart. */
.visual-editor .visual-preview {
  inline-size: 96px;
  block-size: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  margin-block: var(--space-2);
}
.visual-editor .visual-preview img {
  max-inline-size: 100%;
  max-block-size: 100%;
}
.visual-privacy-note {
  max-inline-size: 40ch;
}
.symbol-picker {
  margin-block: var(--space-3);
}
.symbol-search {
  inline-size: 100%;
  padding: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  margin-block-end: var(--space-2);
}
.symbol-count {
  margin-block: 0 var(--space-2);
  font-size: var(--text-sm);
}
.symbol-results {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
  gap: var(--space-2);
  max-block-size: 220px;
  overflow-y: auto;
}
.symbol-option {
  aspect-ratio: 1;
  padding: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  cursor: pointer;
}
.symbol-option img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
}
.file-row,
.audio-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-block: var(--space-2);
}
/* A native file input's min-content is its whole "no file chosen" caption
   (~400px in Chrome) — it pushed every editor that holds the visual picker
   (schedule, tasks, rules) off a 320px phone. A percentage width makes it
   shrinkable (it drops to its own line under the caption instead). */
.file-row input[type="file"] {
  inline-size: 100%;
  min-inline-size: 0;
}
.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  margin-block-start: var(--space-3);
}

/* ---------------------------------------------------------------- Schedule */

.schedule {
  /* #main's padding is outside this box — a plain 100dvh scrolled the page. */
  min-block-size: calc(100dvh - var(--main-pad-top) - var(--main-pad-bottom));
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Focus view */
.focus-view {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  padding-block: var(--space-6);
}
.focus-progress {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  justify-content: center;
}
.focus-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-6);
  border: 3px solid var(--color-primary);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  cursor: pointer;
  transition: transform 300ms ease, opacity 300ms ease;
}
.focus-card.leaving {
  transform: scale(0.9);
  opacity: 0;
}
/* Unlinked tasks render the card as a plain (non-button) div — no popup to
   open, so no pointer affordance; only the הקראה button offers audio. */
.focus-card.unlinked {
  cursor: default;
}
.focus-visual {
  inline-size: 160px;
  block-size: 160px;
  object-fit: contain;
}
.sched-visual-text,
.focus-visual.sched-visual-text {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-2xl);
  font-weight: 700;
  color: var(--color-text-muted);
}
.focus-title {
  font-size: var(--text-2xl);
  text-align: center;
  margin: 0;
}
.focus-time {
  font-size: var(--text-lg);
  color: var(--color-text-muted);
}
.focus-check {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: 120px;
  block-size: 120px;
  border-radius: 50%;
  border: none;
  background: var(--color-success);
  /* White-on-base-success is 2.5:1 (fails even the 3:1 large-text/icon
     floor) — --color-text on the base fill holds 5:1. */
  color: var(--color-text);
  box-shadow: var(--shadow-2);
  cursor: pointer;
  transition: transform 200ms ease;
}
.focus-check:active {
  transform: scale(0.95);
}
.focus-check.checked {
  transform: scale(1.25);
}
.focus-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
}
.focus-done,
.focus-empty {
  text-align: center;
  padding-block: var(--space-12);
}

/* Day list */
.day-list-head {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  flex-wrap: wrap;
  margin-block-end: var(--space-4);
}
.sched-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.sched-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); /* matches the real day-list row, docs/design/stitch-export/_1 */
  font-size: var(--text-lg);
}
/* Done = struck through in the muted text colour. Not opacity: that took
   the text below 4.5:1 (axe, 2026-09-28). Only the picture fades. */
.sched-row.done {
  color: var(--color-text-muted);
  text-decoration: line-through;
}
.sched-row.done :is(.sched-row-time, .sched-row-visual-text) {
  color: var(--color-text-muted);
}
.sched-row.done img.sched-row-visual {
  opacity: 0.55;
}
.sched-row input {
  inline-size: 1.8rem;
  block-size: 1.8rem;
  flex: none;
}
/* The checkbox's own <label> (day-list.js): a --touch-min square around the
   small box — the row can't be the label, the rest of it is a button. */
.sched-row-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  min-inline-size: var(--touch-min);
  min-block-size: var(--touch-min);
  margin: calc(-1 * var(--space-2));
  cursor: pointer;
}
.sched-row-visual {
  inline-size: 44px;
  block-size: 44px;
  object-fit: contain;
  flex: none;
}
.sched-row-title {
  /* A 6rem basis, not 0: in a narrow row (a 360px phone) the "עכשיו" badge
     and the time wrap to the next line instead of squeezing the title into
     a one-letter column. Long words still break rather than overflow. */
  flex: 1 1 6rem;
  min-inline-size: 0;
  overflow-wrap: break-word;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.sched-row-time {
  color: var(--color-text-muted);
}
.sched-row-link {
  color: var(--color-text-muted);
  display: inline-flex;
  flex: none;
}

/* Calendar */
.cal-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-block-end: var(--space-4);
}
.cal-head h1 {
  flex: 1;
  margin: 0;
  font-size: var(--text-lg);
  text-align: center;
}
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-1);
}
.cal-wd {
  text-align: center;
  font-weight: 600;
  color: var(--color-text-muted);
  padding-block: var(--space-1);
}
.cal-cell {
  min-block-size: 72px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.cal-cell.empty {
  border: none;
}
.cal-cell.today {
  border-color: var(--color-primary);
  border-width: 2px;
}
.cal-day {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
/* Wraps instead of ellipsizing, so a bigger text size shows the whole
   event name (the cell grows) rather than a few letters. */
.cal-event {
  font-size: 0.72rem;
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-radius: 0.25rem;
  padding: 0.0625rem 0.1875rem;
  overflow-wrap: anywhere;
  line-height: 1.25;
}

/* Editors */
.sched-item-form,
.copy-day,
.save-template {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-block-start: var(--space-3);
}
.sched-item-form input,
.save-template input {
  padding: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.template-picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: flex-start;
}
.template-picker select {
  padding: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
}
/* Two labelled groups inside the AAC editor's "ברירות מחדל ללוח" card
   (aac/editor.js's templateGroup): the bundled starter boards, then the
   caregiver's own saved ones — only the latter get a מחק button. */
.tpl-group {
  margin-block-start: var(--space-4);
}
.tpl-group-head {
  margin: 0 0 var(--space-2);
  font-size: var(--text-base);
}
.tpl-level {
  flex: none;
  padding-inline: var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* Focus view — browse arrows, status chip, current-task marker */
.focus-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
}
.focus-nav {
  inline-size: 64px;
  block-size: 64px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 150ms ease;
}
.focus-nav:active {
  transform: scale(0.92);
}
.focus-nav:disabled {
  opacity: 0.3;
  cursor: default;
}
.focus-status {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: 2.5rem;
}
.focus-chip {
  font-size: var(--text-base);
  font-weight: 700;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  border: 2px solid var(--color-border-strong);
  color: var(--color-text-muted);
}
.focus-chip.now {
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-color: var(--color-primary);
}
.focus-check.done {
  background: var(--color-surface);
  border: 2px solid var(--color-border-strong);
  color: var(--color-text-muted);
  cursor: default;
}
.dot.viewing {
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* Day list — current-task row + tap-to-focus target */
.sched-row-main {
  flex: 1;
  /* At a large text size the time and the "עכשיו" badge wrap under the
     title instead of pushing the row past the screen edge. */
  min-inline-size: 0;
  flex-wrap: wrap;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  text-align: start;
  cursor: pointer;
}
.sched-row.current {
  border-color: var(--color-primary);
  border-width: 2px;
}
.sched-row-now {
  font-size: var(--text-sm);
  font-weight: 700;
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-radius: var(--radius-pill);
  padding: 0 var(--space-2);
  flex: none;
}

@media (prefers-reduced-motion: reduce) {
  .focus-card,
  .focus-check,
  .focus-nav {
    transition: none;
  }
}

/* ------------------------------------------------- Rules / tokens / rewards */

.rules-screen {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.token-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-lg);
  font-weight: 700;
  background: var(--color-warning);
  /* White-on-base-warning is 2.2:1 (fails even the 3:1 large-text floor) —
     --color-text on the base fill holds 5.8:1. */
  color: var(--color-text);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
/* A "n/total completed" pill (nav bar) — same shape/weight as .token-badge,
   on --color-success so it reads as a sibling, not a louder cousin. Shared
   by My Tasks and Reading & Writing. */
.count-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-lg);
  font-weight: 700;
  background: var(--color-success);
  /* Same reasoning as .token-badge: white-on-base-success fails the 3:1
     floor, --color-text on the base fill holds (docs/accessibility.md). */
  color: var(--color-text);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.queue-badge {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: var(--text-base);
  font-weight: 700;
  /* Base --color-danger can't clear 4.5:1 for normal text against either
     black or white (its own luminance sits between the two) — ink-on-surface
     holds >= 6.4:1 in both themes instead of filling with the raw hue. */
  background: var(--color-surface);
  color: var(--color-danger-ink);
  border: 1.5px solid var(--color-danger);
  border-radius: var(--radius-pill);
  padding: 0 var(--space-2);
}

.rules-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.rule-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 2px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  text-align: start;
  cursor: pointer;
}
.rule-visual {
  inline-size: 64px;
  block-size: 64px;
  object-fit: contain;
  flex: none;
}
.rule-visual-text {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-text-muted);
}
.rule-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.rule-text strong {
  font-size: var(--text-lg);
}

.reward-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: 150px;
  padding: var(--space-3);
  border: 2px solid var(--color-primary);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  cursor: pointer;
}
/* Locked = can't afford yet. Still readable (name + price): dashed border
   and faded picture, not a see-through tile. */
.reward-tile.locked {
  border-color: var(--color-border);
  border-style: dashed;
  color: var(--color-text-muted);
}
.reward-tile.locked :is(img, .icon) {
  opacity: 0.5;
}
.reward-visual {
  inline-size: 64px;
  block-size: 64px;
  object-fit: contain;
}
.reward-cost {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-weight: 700;
  color: var(--color-warning-ink);
}

.award-form,
.tx-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
.award-form input {
  inline-size: 8rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.tx-list {
  flex-direction: column;
  align-items: stretch;
  list-style: none;
  padding: 0;
  margin-block-start: var(--space-3);
}
.tx-list li {
  padding: var(--space-1) 0;
  border-block-start: 1px solid var(--color-border);
}
.tx-pos {
  color: var(--color-success-ink);
  font-weight: 700;
}
.tx-neg {
  color: var(--color-danger-ink);
  font-weight: 700;
}
/* Inactive = muted text, faded picture. Not opacity on the whole row: that
   took its text to ~2.8:1 (axe, 2026-09-28) though it's still content. */
.editor-card-row.inactive,
.editor-card-row.inactive .muted {
  color: var(--color-text-muted);
}
.editor-card-row.inactive :is(img, .icon) {
  opacity: 0.5;
}

/* Read-aloud highlight — which rule (or the bonus line) is speaking now. */
.rule-card.speaking,
.rules-bonus.speaking {
  border-color: var(--color-primary);
  outline: 3px solid var(--color-primary);
  outline-offset: 2px;
}

/* The child-facing closing line ("אם שמרת על הכללים…") plus the caregiver's
   PIN-gated claim button. The container itself is never interactive. */
.rules-bonus {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  margin-block-start: var(--space-3);
  padding: var(--space-4);
  border: 2px solid var(--color-border);
  border-block-start-width: 3px;
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  font-size: var(--text-lg);
  font-weight: 700;
}
.rules-bonus-text {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.rules-bonus .icon {
  flex: none;
  color: var(--color-warning-ink);
}
.rules-bonus-claim {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
  padding: var(--space-2) var(--space-5);
  border: none;
  border-radius: var(--radius-md);
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  font-size: var(--text-base);
  font-weight: 700;
  cursor: pointer;
}
.rules-bonus-claim .icon {
  color: currentColor;
}
.rules-bonus-done {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--color-success-ink);
}
.rules-bonus-done .icon {
  color: currentColor;
}

/* Caregiver: daily-bonus config + grant button, under the award form. */
.bonus-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-block-start: var(--space-3);
  padding-block-start: var(--space-3);
  border-block-start: 1px solid var(--color-border);
}

/* Caregiver: the token ledger, collapsed until asked for. */
.tx-history {
  margin-block-start: var(--space-3);
}
.tx-history summary {
  cursor: pointer;
  padding: var(--space-2) 0;
  font-weight: 700;
}
.tx-history .tx-list {
  margin-block-start: var(--space-2);
}

/* Caregiver dashboard: per-child module toggles + edit links, and the
   devices list, both collapsed until asked for (views/dashboard.js) — the
   same native <details> pattern as .tx-history above, sized to the 44px
   caregiver touch-target floor (.editor-card-head already uses the same
   value) since neither .tx-history's summary nor a bare native one meets it.
   The child card's <summary> IS its .child-card-head (avatar + name) — there
   is no separate "more" label; tapping the name/avatar is what opens it. */
.child-more,
.devices-details {
  margin-block-start: var(--space-3);
}
/* Both are their card's only/first child — no extra gap above the head/label
   that every other card's content doesn't have. */
.card > .child-more:first-child,
.card > .devices-details:first-child {
  margin-block-start: 0;
}
.devices-details summary {
  cursor: pointer;
  padding: var(--space-2) 0;
  font-weight: 700;
  min-block-size: 44px;
  display: flex;
  align-items: center;
}
/* .child-card-head (app.css above) already sets display:flex/align-items —
   this only adds what a bare <summary> needs on top of that. */
.child-more summary {
  cursor: pointer;
  min-block-size: 44px;
}
.child-more[open] .toggle-list,
.child-more[open] .child-card-actions {
  margin-block-start: var(--space-3);
}
.devices-details[open] .editor-card-list {
  margin-block-start: var(--space-2);
}

/* The manager's area (dashboard.js orgCard): each area is a card whose
   title opens it, and each staff member / unit row opens by tapping its
   name — the same tap-the-name pattern as the client cards. */
.org-manage > h2 {
  margin-block: var(--space-6) var(--space-1);
}
.mgr-section {
  padding-block: 0;
  margin-block: var(--space-3);
}
.mgr-summary,
.mgr-row-summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  cursor: pointer;
  list-style: none;
}
.mgr-summary::-webkit-details-marker,
.mgr-row-summary::-webkit-details-marker {
  display: none;
}
.mgr-summary {
  min-block-size: 60px;
  font-size: var(--text-lg);
  font-weight: 700;
}
.mgr-title {
  flex: 1;
}
.mgr-summary .icon,
.mgr-row-summary .icon {
  flex: none;
  transition: transform 150ms ease;
}
.mgr-section[open] > .mgr-summary .icon,
.mgr-row[open] > .mgr-row-summary .icon {
  transform: rotate(-90deg);
}
.mgr-body {
  padding-block-end: var(--space-4);
}
/* A block that brings its own heading, now shown as the area's title */
.mgr-body > .partners-block > h4:first-child {
  display: none;
}
.mgr-row {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.mgr-row-summary {
  min-block-size: 48px;
  padding: var(--space-2);
}
.mgr-row-summary .editor-card-label {
  flex: 1;
}
.mgr-row-body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2) var(--space-3);
}
.unit-guides {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  flex: 1 0 100%;
}
.unit-guide-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding-inline-start: var(--space-2);
  border-radius: 999px;
  background: var(--color-surface-sunken);
}
.overview-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: var(--touch-min);
  margin-block-end: var(--space-4);
}
@media (prefers-reduced-motion: reduce) {
  .mgr-summary .icon,
  .mgr-row-summary .icon {
    transition: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rule-card,
  .rules-bonus {
    transition: none;
  }
}

/* ------------------------------------------------------------ Calming zone */

.calming { display: flex; flex-direction: column; gap: var(--space-4); }

/* A grid so all nine loops fit one screen under the nav bar + tab strip. */
.calm-sounds {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2);
}
.calm-sound {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-1);
  min-block-size: clamp(80px, 13vh, 116px);
  padding: var(--space-2);
  border: 2px solid var(--color-border); border-radius: var(--radius-lg);
  background: var(--color-surface); font-size: var(--text-base);
  text-align: center; cursor: pointer;
}
.calm-sound.active { border-color: var(--color-primary); background: var(--color-primary-soft); }
.calm-emoji { font-size: 1.8rem; }
.calm-sound .icon { font-size: 1.4rem; }
.calm-state {
  position: absolute;
  inset-block-start: var(--space-1); inset-inline-end: var(--space-1);
}
@media (max-inline-size: 380px) {
  .calm-sounds { grid-template-columns: repeat(2, 1fr); }
}

.breathing {
  display: flex; flex-direction: column; align-items: center;
  gap: var(--space-6); padding-block: var(--space-6);
}
.breath-circle {
  inline-size: 240px; block-size: 240px; border-radius: 50%;
  background: var(--color-primary); opacity: 0.35;
  transform: scale(0.35); /* rest = small; grows into the in-breath */
  transition: transform 4s ease, opacity 4s ease;
}
.breath-circle[data-phase="in"]  { transform: scale(1);    opacity: 0.7;  transition-duration: 4s; }
.breath-circle[data-phase="hold"] { transform: scale(1);    opacity: 0.7;  transition-duration: 2s; }
.breath-circle[data-phase="out"] { transform: scale(0.35); opacity: 0.35; transition-duration: 6s; }
.breath-label { font-size: var(--text-xl); }
.breath-controls {
  display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
  inline-size: 100%;
}
@media (prefers-reduced-motion: reduce) {
  .breath-circle { transition: none; }
}

.memory-head { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; margin-block-end: var(--space-3); }
.memory-grid {
  display: grid; grid-template-columns: repeat(var(--cols, 4), 1fr);
  gap: var(--space-2);
}
.memory-card {
  aspect-ratio: 1; border: 2px solid var(--color-border);
  border-radius: var(--radius-md); background: var(--color-surface);
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.memory-card.shown { background: var(--color-bg); border-color: var(--color-primary); }
.memory-card img { inline-size: 70%; block-size: 70%; object-fit: contain; }
.memory-back { font-size: var(--text-xl); font-weight: 700; color: var(--color-text-muted); }

/* ----------------------------------------------------------- Social stories */

.story-list { display: flex; flex-direction: column; gap: var(--space-3); }
.story-card {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4); border: 2px solid var(--color-border);
  border-radius: var(--radius-lg); background: var(--color-bg);
  font-size: var(--text-lg); cursor: pointer; text-align: start;
}
.story-emoji { font-size: 2rem; }

.story-reader { display: flex; flex-direction: column; gap: var(--space-4); align-items: center; }
.story-topbar { display: flex; flex-wrap: wrap; justify-content: space-between; inline-size: 100%; align-items: center; }
.story-image {
  inline-size: 100%; max-inline-size: 26.25rem; aspect-ratio: 4/3;
  object-fit: cover; border-radius: var(--radius-lg); background: var(--color-surface);
}
.story-image-symbol { object-fit: contain; padding: var(--space-4); background: #fff; }
.story-image-blank { display: flex; align-items: center; justify-content: center; font-size: 4rem; }
.story-text {
  font-size: var(--text-xl); line-height: 1.5; text-align: center;
  max-inline-size: 30rem; cursor: pointer;
}
.story-nav { display: flex; gap: var(--space-3); flex-wrap: wrap; justify-content: center; }

.chat-log {
  display: flex; flex-direction: column; gap: var(--space-2);
  /* 20rem, not 320px, so it grows with the text size; and never more than
     half the visible height, so on a landscape phone (or with the keyboard
     up) the input under it stays on screen. */
  max-block-size: min(20rem, 50dvh); overflow-y: auto; margin-block: var(--space-3);
}
.chat-msg {
  max-inline-size: 80%; padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md); font-size: var(--text-base);
}
.chat-msg.bot { background: var(--color-surface); align-self: flex-start; }
.chat-msg.me { background: var(--color-primary); color: var(--color-primary-contrast); align-self: flex-end; }
/* Wraps, and the input may shrink: a text input's intrinsic width (~20
   characters) plus the send button(s) is wider than a 320px phone. */
.chat-form { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chat-form input {
  flex: 1 1 10rem; min-inline-size: 0;
  padding: var(--space-2); border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}

.slot-checklist { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.slot-checklist li { display: flex; flex-wrap: wrap; gap: var(--space-2); font-size: var(--text-sm); }
.slot-checklist li.pending .slot-label { color: var(--color-text-muted); }
.slot-checklist li.done .slot-label { color: var(--color-primary); font-weight: 600; }
.slot-checklist .slot-value { color: var(--color-text-muted); }

.story-preview { display: flex; flex-direction: column; gap: var(--space-3); }
.review-chip { align-self: flex-start; font-size: var(--text-sm); color: var(--color-text-muted); margin: 0; }
.review-chip.revised { color: var(--color-primary); font-weight: 600; }
.slp-notes { border-inline-start: 4px solid var(--color-primary); padding-inline-start: var(--space-3); }
.slp-notes ul { margin-block: var(--space-2); padding-inline-start: var(--space-4); }
.slow-op .art-progress { flex-direction: column; align-items: stretch; margin-block-start: var(--space-3); }
.slow-op .art-progress progress { inline-size: 100%; }
.art-progress { display: flex; align-items: center; gap: var(--space-2); }
.art-progress progress { inline-size: 12rem; }
.preview-pages { display: flex; flex-direction: column; gap: var(--space-3); }
.preview-page { display: flex; gap: var(--space-3); align-items: flex-start; }
.preview-page img, .preview-page .ph {
  inline-size: 96px; block-size: 96px; border-radius: var(--radius-md);
  flex: none; object-fit: cover;
}
.preview-page img.preview-symbol { object-fit: contain; background: #fff; padding: var(--space-2); }
.preview-page-col { flex: 1; min-inline-size: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.preview-symbol-row { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; }
.preview-page .ph {
  display: grid; place-items: center; font-size: var(--text-xl);
  background: var(--color-surface);
}
.preview-page .page-text-edit {
  flex: 1; min-inline-size: 0; font: inherit; font-size: var(--text-base);
  line-height: 1.5; padding: var(--space-2); border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm); resize: vertical;
}
.story-title-edit {
  font-size: var(--text-lg); font-weight: 700; inline-size: 100%;
  padding: var(--space-2); border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.story-preview-actions { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }

/* ------------------------------------------------------- Reading & writing */

.learning { display: flex; flex-direction: column; gap: var(--space-4); }
/* Lets the flex column actually shrink to the phone-portrait viewport instead
   of overflowing to its content's min-content width (the default `min-width:
   auto` on a flex item) — see .reading-body/.writing-input below, which are
   the wide content that min-inline-size:0 here allows to be constrained. */
.learn-host { min-inline-size: 0; }
.lesson-list { display: flex; flex-direction: column; gap: var(--space-3); }
.lesson-item {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4); border: 2px solid var(--color-border);
  border-radius: var(--radius-lg); background: var(--color-bg);
  font-size: var(--text-lg); cursor: pointer; text-align: start;
}
.lesson-level {
  font-size: var(--text-sm); background: var(--color-surface);
  border-radius: var(--radius-pill); padding: 2px var(--space-2); color: var(--color-text-muted);
}
.lesson-top { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; margin-block-end: var(--space-3); }
.lesson-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-block-start: var(--space-4); }
.reading-body {
  font-size: var(--text-xl); line-height: 1.9; text-align: start;
  background: var(--color-surface); border-radius: var(--radius-lg);
  padding: var(--space-6);
}
.lesson-result { text-align: center; padding-block: var(--space-8); display: flex; flex-direction: column; gap: var(--space-3); }
.lesson-result-gentle {
  display: flex; flex-direction: column; align-items: center; gap: var(--space-3);
  color: var(--color-text-muted);
}
.writing-view { display: flex; flex-direction: column; gap: var(--space-3); }
.writing-input {
  padding: var(--space-3); font-size: var(--text-lg); text-align: start;
  border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm);
  inline-size: 100%;
}
.writing-hint { font-size: var(--text-xl); margin-block: var(--space-3); }
/* The Android/iOS soft keyboard covers the bottom of the viewport once the
   input is focused — without this the "בדיקה" submit button ends up hidden
   underneath it with no way to reach it short of dismissing the keyboard. */
.writing-view button[type="submit"] {
  position: sticky;
  inset-block-end: var(--space-2);
}

/* Kiosk-tablet sizes below are too large for the phone-portrait secondary
   target (docs/design.md) — same reasoning as .tile-grid's breakpoint above.
   Text stays >= --text-base; touch targets keep their --touch-min floor. */
@media (max-width: 600px) {
  .reading-body {
    font-size: var(--text-lg);
    line-height: 1.7;
    padding: var(--space-4);
  }
  .writing-hint {
    font-size: var(--text-lg);
  }
  .lesson-item {
    font-size: var(--text-base);
    padding: var(--space-3);
  }
}

/* Level-based tab: 3-level selector, then a progress row, then the task list. */
.learning-tab { display: flex; flex-direction: column; gap: var(--space-3); }
.learn-progress {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface); border-radius: var(--radius-lg);
  font-weight: 600;
}
.learn-claim {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-1); inline-size: auto; min-block-size: var(--touch-min);
  margin: 0; padding: var(--space-2) var(--space-4);
}
.learn-claim .icon { color: currentColor; }
.learning-editor { display: flex; flex-direction: column; gap: var(--space-3); }
.learning-editor textarea {
  font: inherit; padding: var(--space-2); resize: vertical;
  border: 1px solid var(--color-border-strong); border-radius: var(--radius-sm);
}

/* pin.inline — the inline caregiver approval on a child screen (pin-gate.js)
   is the same pad as "החלפת משתמש": .pin-card / .pin-dots / .pin-keys above. */

/* ------------------------------------------------------------ Typing board
   "הפתקים שלי" — free-composition notes. The block textareas sit borderless on
   one .note-sheet so the stack reads as a single writing surface, not a form. */
.typing-screen,
.typing {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.note-new {
  align-self: flex-start;
  min-block-size: var(--touch-min);
}
.note-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.note-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  padding: var(--space-4);
  border: 2px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  font-size: var(--text-lg);
  text-align: start;
  cursor: pointer;
}
.note-card-title {
  font-weight: var(--font-weight-heading);
}
.note-card-meta {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.note-card-unsynced {
  font-size: var(--text-sm);
  color: var(--color-warning-ink);
}

.note-editor-top {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: center;
  justify-content: space-between;
  margin-block-end: var(--space-3);
}
.note-top-actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.note-toolbar {
  position: sticky;
  inset-block-start: var(--safe-top);
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  justify-content: flex-start;
  padding-block: var(--space-2);
  margin-block-end: var(--space-2);
  background: var(--color-bg);
  border-block-end: 1px solid var(--color-border);
}
.note-style-group {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
}
.note-size-group {
  display: flex;
  gap: var(--space-1);
  margin-inline-start: auto;
}
.note-style-btn {
  min-block-size: var(--touch-min);
  padding-inline: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  font-size: var(--text-sm);
  cursor: pointer;
}
.note-style-btn[aria-checked="true"] {
  background: var(--color-secondary-soft);
  border-color: var(--color-secondary);
  font-weight: 600;
}
.note-font-select {
  min-block-size: var(--touch-min);
  padding-inline: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  font: inherit;
}

.note-sheet {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  min-block-size: 55vh;
  font-family: var(--note-font, var(--font-sans));
}
.note-sheet[data-font="assistant"] {
  --note-font: "Assistant", "Rubik", system-ui, sans-serif;
}
.note-sheet[data-font="heebo"] {
  --note-font: "Heebo", "Rubik", system-ui, sans-serif;
}
.note-title-input {
  inline-size: 100%;
  border: 0;
  border-block-end: 1px solid var(--color-border);
  background: transparent;
  font-family: inherit;
  font-size: calc(var(--text-xl) * var(--note-scale, 1));
  font-weight: var(--font-weight-heading);
  padding-block: var(--space-2);
  margin-block-end: var(--space-3);
}
.note-row {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
}
.note-blk,
.note-blk-ro {
  flex: 1;
  inline-size: 100%;
  border: 0;
  background: transparent;
  font-family: inherit;
  text-align: start;
  resize: none;
  overflow: hidden;
  overflow-wrap: anywhere;
  padding-block: var(--space-1);
}
.note-blk:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.note-h1 {
  font-size: calc(var(--text-2xl) * var(--note-scale, 1));
  font-weight: var(--font-weight-heading);
  line-height: 1.3;
}
.note-h2 {
  font-size: calc(var(--text-xl) * var(--note-scale, 1));
  font-weight: var(--font-weight-heading);
  line-height: 1.4;
}
.note-p {
  font-size: calc(var(--text-lg) * var(--note-scale, 1));
  line-height: 1.8;
}
.note-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: var(--touch-min);
  min-block-size: var(--touch-min);
  padding-inline: var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
  font-size: var(--text-sm);
  cursor: pointer;
}
.note-del {
  visibility: hidden;
}
.note-row:focus-within .note-del {
  visibility: visible;
}
.note-add-row {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-block-size: var(--touch-min);
  padding-inline: var(--space-4);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  background: transparent;
  font: inherit;
  cursor: pointer;
}
.note-status {
  min-block-size: 1.5em;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.note-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
}

/* ------------------------------------------------------------ My Tasks
   "המשימות שלי" — a checklist the child ticks off, mirroring the schedule
   day-list row so the two modules feel the same. */
.task-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.task-list-head {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  flex-wrap: wrap;
}
.task-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.task-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  font-size: var(--text-lg);
  min-block-size: var(--touch-min); /* the row is the checkbox's <label> */
  cursor: pointer;
}
/* Done = struck through in the muted text colour. Not opacity: that took
   the text below 4.5:1 (axe, 2026-09-28). Only the picture fades. */
.task-row.done {
  color: var(--color-text-muted);
  text-decoration: line-through;
}
.task-row.done :is(.task-row-time, .task-row-visual-text) {
  color: var(--color-text-muted);
}
.task-row.done img.task-row-visual {
  opacity: 0.55;
}
.task-row input {
  inline-size: 1.8rem;
  block-size: 1.8rem;
  flex: none;
}
.task-row-visual {
  inline-size: 44px;
  block-size: 44px;
  object-fit: contain;
  flex: none;
}
.task-row-title {
  flex: 1;
  min-inline-size: 0; /* shrink and wrap at a large text size, not overflow */
  overflow-wrap: anywhere;
}
.task-groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.task-group-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-end: var(--space-2);
}
.task-group-visual {
  inline-size: 28px;
  block-size: 28px;
  object-fit: contain;
  flex: none;
}
.task-group-title {
  font-weight: 600;
  color: var(--color-text-muted);
}
.task-group-filter {
  color: var(--color-text-muted);
}
.task-reward {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}
.task-claim {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  inline-size: auto;
  min-block-size: var(--touch-min);
  margin: 0;
  padding: var(--space-2) var(--space-4);
}
.task-claim .icon {
  color: currentColor;
}
/* המשימות שלי — the day's lists as tiles, one list one task at a time
   (modules/tasks/index.js + focus.js; the focus view reuses .focus-*). */
.task-tiles {
  margin-block-start: var(--space-4);
}
.task-tile {
  position: relative;
  min-block-size: 220px;
}
.task-tile-visual {
  inline-size: 96px;
  block-size: 96px;
  object-fit: contain;
}
.task-tile-name {
  text-align: center;
}
.task-tile-dots {
  gap: var(--space-1);
}
.task-tile-count {
  font-size: var(--text-lg);
  color: var(--color-text-muted);
}
.task-tile.done {
  background: var(--color-bg);
  box-shadow: none;
  border: 2px solid var(--color-success);
}
.task-tile.done .task-tile-visual {
  opacity: 0.6;
}
.task-tile-done {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-base);
}
.task-weekly-tag {
  display: inline-block;
  padding: 2px var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  font-size: var(--text-sm);
  font-weight: 600;
}
.task-tile .task-weekly-tag {
  position: absolute;
  inset-block-start: var(--space-3);
  inset-inline-start: var(--space-3);
}
.task-open-name {
  text-align: center;
  margin-block: var(--space-2) 0;
}
.task-focus .focus-card {
  min-inline-size: min(20rem, 70vw);
}
@media (prefers-reduced-motion: reduce) {
  .task-focus .focus-card,
  .task-focus .focus-check {
    transition: none;
  }
}

.tasks-editor {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* "מאגר משימות" (modules/tasks/bank.js) */
.task-bank h4 {
  margin-block: var(--space-3) var(--space-2);
}
.task-bank-levels {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.task-bank-list-row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--space-2);
}
.task-bank-list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  min-block-size: var(--touch-min-caregiver);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.task-bank-list img {
  inline-size: 48px;
  block-size: 48px;
}
.task-bank-cat {
  border-block-start: 1px solid var(--color-border);
}
.task-bank-cat summary {
  min-block-size: var(--touch-min-caregiver);
  display: flex;
  align-items: center;
  cursor: pointer;
  font-weight: 600;
}
.task-bank-cat summary::-webkit-details-marker {
  display: none;
}
.task-bank-cat summary::before {
  content: "◂"; /* points forward (inline-end) in RTL */
  inline-size: 1.25rem;
  flex: none;
}
.task-bank-cat[open] summary::before {
  content: "▾";
}
.task-bank-tasks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-1) var(--space-3);
}
.task-bank-task {
  padding-block: var(--space-1);
}
.task-bank-pick,
.task-bank-steps {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min-caregiver);
  cursor: pointer;
}
.task-bank-pick input,
.task-bank-steps input {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  flex: none;
}
.task-bank-pick img {
  inline-size: 40px;
  block-size: 40px;
  flex: none;
}
.task-bank-steps {
  margin-inline-start: var(--space-6);
  font-size: var(--text-sm);
}
.task-bank-steps:has(input:disabled) {
  opacity: 0.5;
  cursor: default;
}
.task-bank-steplist {
  margin-block: 0;
  margin-inline-start: var(--space-6);
  font-size: var(--text-sm);
}
.task-bank-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-block-start: var(--space-3);
  position: sticky;
  inset-block-end: 0;
  padding-block: var(--space-2);
  background: var(--color-surface);
}
.task-bank-actions select {
  min-block-size: var(--touch-min-caregiver);
}

/* ------------------------------------------------------------ בוא נצייר
   The painting surface is ALWAYS square, letterboxed, with a hard #fff paper
   in both themes — never --color-surface, which would invert the whole module.
   Three stacked layers: white regions (hit-testable) / transparent ink canvas
   (pointer-events:none — the eraser's destination-out would punch through a
   painted paper) / black outline on top. */
.paint-screen,
.paint-host {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-block-size: 0;
}
.paint-editor,
.paint-gallery,
.paint-chooser {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3);
}

.paint-surface {
  position: relative;
  aspect-ratio: 1;
  inline-size: min(100%, 90vmin);
  margin-inline: auto;
  background: #fff; /* paper — hard-coded, both themes */
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
  touch-action: none; /* or the browser claims the drag as a pan */
  overscroll-behavior: contain;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.paint-regions,
.paint-ink,
.paint-lines {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
}
.paint-ink,
.paint-lines {
  pointer-events: none;
}
.paint-regions [data-region] {
  pointer-events: all;
  cursor: pointer;
}
.paint-regions [data-region]:focus-visible {
  outline: 3px solid var(--color-focus);
}

.paint-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
}
.paint-tools,
.paint-sizes,
.paint-acts {
  display: flex;
  gap: var(--space-2);
}
.paint-tool,
.paint-size,
.paint-act {
  min-block-size: var(--touch-min);
  min-inline-size: var(--touch-min);
  padding-inline: var(--space-3);
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
}
.paint-tool[aria-pressed="true"],
.paint-size[aria-pressed="true"] {
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  border-color: var(--color-primary);
}
.paint-size-dot {
  display: block;
  inline-size: var(--d, 10px);
  block-size: var(--d, 10px);
  border-radius: var(--radius-pill);
  background: currentColor;
}
.paint-act:disabled {
  opacity: 0.4;
}

.paint-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.paint-swatch {
  inline-size: var(--touch-min);
  block-size: var(--touch-min);
  border-radius: var(--radius-md);
  border: 2px solid var(--color-border-strong); /* visible even for white in dark mode */
  background: var(--sw, #000);
  padding: 0;
}
.paint-swatch[aria-pressed="true"] {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

.paint-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.paint-status {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}
.paint-done {
  min-block-size: var(--touch-min);
  padding-inline: var(--space-6);
}

/* gallery + chooser */
.paint-new {
  min-block-size: var(--touch-min);
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.paint-grid,
.paint-page-grid,
.paint-viewer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--space-3);
}
.paint-thumb-card,
.paint-page-card,
.paint-viewer-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2);
  border: 2px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  min-block-size: var(--touch-min);
}
.paint-thumb-img,
.paint-page-img,
.paint-thumb-blank,
.paint-viewer-thumb {
  inline-size: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  background: #fff;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
}
.paint-thumb-title,
.paint-thumb-badge {
  font-size: var(--text-sm);
  text-align: center;
}
.paint-thumb-badge {
  color: var(--color-warning-ink);
}
.paint-chooser-head,
.paint-detail-acts {
  display: flex;
  gap: var(--space-3);
  align-items: center;
}
.paint-detail-acts {
  flex-wrap: wrap;
}
.paint-detail-img,
.paint-page-chips {
  inline-size: 100%;
}
.paint-page-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.paint-page-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-1);
}
.paint-page-chip img {
  inline-size: 44px;
  block-size: 44px;
  background: #fff;
  border-radius: var(--radius-sm);
}
.paint-detail-img {
  border-radius: var(--radius-md);
  background: #fff;
}

@media (prefers-reduced-motion: no-preference) {
  :root:not([data-a11y-motion]) .paint-tool,
  :root:not([data-a11y-motion]) .paint-swatch {
    transition: background 0.12s ease;
  }
}

/* Print rules live in css/print.css (media="print"). */

/* Operator dashboard (views/operator.js) — owner-only analytics — and the
   org's wide report pages. Wider than the caregiver column so tables and
   charts stay readable: about 70rem on a desktop; below that (tablets) the
   page simply takes the full width inside #main's gutters. */
#main:has(.operator),
#main:has(.reports-wide) {
  max-inline-size: 70rem;
}
.op-actions {
  display: flex;
  gap: var(--space-2);
}
.op-note {
  font-size: var(--text-sm);
  margin-block-end: var(--space-4);
}
.op-month {
  position: sticky;
  inset-block-start: 0;
  z-index: 2;
  padding-block: var(--space-2);
  background: var(--color-bg);
}
.op-month .period-label {
  min-inline-size: 9rem;
  text-align: center;
  font-size: var(--text-lg);
}
.op-month input[type="month"] {
  padding: var(--space-2);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}
.op-row-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--space-3);
  margin-block-end: var(--space-4);
}
.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}
.stat-label {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.stat-value {
  font-size: var(--text-xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.stat-hint {
  font-size: var(--text-sm);
}
.stat-good .stat-value {
  color: var(--color-success-ink);
}
.stat-bad .stat-value {
  color: var(--color-danger-ink);
}
.chart {
  margin: 0 0 var(--space-4);
}
.chart svg {
  display: block;
  inline-size: 100%;
  block-size: auto;
  /* An edge axis label centred on the first/last point may reach past the
     plot; let it show rather than clip (charts.js pads for the text). */
  overflow: visible;
}
/* rem, so it follows the text-size setting; charts.js draws the SVG at its
   real width (1 unit = 1px) and thins the labels to fit. */
.chart-axis,
.chart-value {
  font-size: 0.75rem;
  fill: var(--color-text-muted);
}
.chart-value {
  fill: var(--color-text);
}
.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  list-style: none;
  padding: 0;
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
}
.chart-legend li {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
.chart-swatch {
  inline-size: 12px;
  block-size: 12px;
  border-radius: 3px;
}
.hbars {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-4);
  display: grid;
  gap: var(--space-2);
}
.hbars li {
  display: grid;
  grid-template-columns: minmax(5rem, 10rem) 1fr auto;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
}
.hbar-label {
  min-inline-size: 0;
  overflow-wrap: anywhere;
}
/* A phone (or 200% text) can't spare a label column beside the bar: the
   label takes its own line, the bar and number go under it. */
@media (max-width: 600px) {
  .hbars li {
    grid-template-columns: 1fr auto;
    gap: var(--space-1) var(--space-3);
  }
  .hbar-label {
    grid-column: 1 / -1;
  }
}
.hbar-track {
  block-size: 12px;
  background: var(--color-surface-sunken);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.hbar-fill {
  display: block;
  block-size: 100%;
  border-radius: var(--radius-pill);
}
.hbar-value {
  text-align: end;
  font-variant-numeric: tabular-nums;
}
/* Sideways-scrolling tables (ui.js dataTable / scrollHint). The frame
   shades an edge while columns hide past it; --table-bg is what the sticky
   first column paints so scrolled cells don't show through it. The app is
   RTL-only, so the inline end is the physical left in the gradients. */
.scroll-hint {
  position: relative;
  margin-block-end: var(--space-4);
  --table-bg: var(--color-bg);
  --edge-shade: color-mix(in srgb, var(--color-text) 22%, transparent);
}
.card .scroll-hint {
  --table-bg: var(--color-surface);
}
.scroll-hint::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: var(--space-6);
  background: linear-gradient(to left, var(--edge-shade), transparent);
  pointer-events: none;
  opacity: 0;
}
.scroll-hint[data-more-end]::after {
  opacity: 1;
}
.op-table-wrap {
  overflow-x: auto;
}
/* The first column (the name) stays in view while the rest scrolls. */
.op-table th:first-child,
.op-table td:first-child {
  position: sticky;
  inset-inline-start: 0;
  z-index: 1;
  background: var(--table-bg, var(--color-bg));
}
/* A long client name (the row's open button) wraps instead of pushing every
   other column away; dates and numbers in a first column stay on one line. */
.op-table .row-open {
  white-space: normal;
  min-inline-size: 6rem;
  max-inline-size: 12rem;
}
.scroll-hint[data-more-start] .op-table th:first-child,
.scroll-hint[data-more-start] .op-table td:first-child {
  box-shadow: -6px 0 6px -4px var(--edge-shade);
}
.op-table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.op-table th,
.op-table td {
  padding: var(--space-2) var(--space-3);
  text-align: start;
  border-block-end: 1px solid var(--color-border);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.op-table th {
  color: var(--color-text-muted);
  font-weight: 600;
}
/* A sortable header: the button fills the cell's height, so the whole
   header is the 44px target, not the ~20px line of text. */
.op-table th:has(> .th-sort) {
  padding-block: 0;
}
.th-sort {
  display: inline-flex;
  align-items: center;
  inline-size: 100%;
  min-block-size: var(--touch-min-caregiver);
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.op-table .btn-link {
  min-block-size: var(--touch-min-caregiver);
  padding: var(--space-1) var(--space-2);
}
/* A clickable row's first-cell button (dataTable's onRow): the keyboard /
   screen-reader way in, and on a phone the obvious thing to tap. */
.op-table .row-open {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--touch-min-caregiver);
}
.plan-badge {
  display: inline-block;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-surface-sunken);
}
.plan-personal,
.plan-family,
.plan-organization {
  background: var(--color-primary-soft);
}
.op-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
}
.op-expense-form {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0 var(--space-3);
  align-items: end;
  margin-block-start: var(--space-3);
}
.op-expense-form .btn-primary {
  margin-block-end: var(--space-4);
}

/* ------------------------------------------------- Client file (תיק מטופל) */
/* modules/reports/: the staff-facing file, the daily-report form, the ABC
   incident dialog and saved summaries. Ratings are five 60px buttons — a
   guide fills these on a tablet at the end of a shift, often one-handed. */
.dash-sub {
  font-size: var(--text-base);
  font-weight: 400;
}
.report-tabs {
  margin-block: var(--space-3) var(--space-4);
}
/* On a phone the client file's tabs (היום / דיווחים / …) and a profession
   screen's tabs stay one swipeable row instead of wrapping into a block of
   chips, each a finger-sized target. */
@media (max-width: 600px) {
  .report-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    /* room for the focus ring, which the scroller would otherwise clip */
    padding: var(--space-1);
    margin-inline: calc(-1 * var(--space-1));
  }
  .report-tabs .chip {
    flex: none;
    min-block-size: var(--touch-min-caregiver, 44px);
    white-space: nowrap;
  }
}
.file-body > * + * {
  margin-block-start: var(--space-3);
}
.period-picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-block-end: var(--space-3);
}
.period-picker .child-switch {
  margin-block: 0;
}
.period-nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.period-nav input[type="date"] {
  padding: var(--space-2);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
}
.period-label {
  font-weight: 600;
}
.report-section h3 {
  margin-block-start: 0;
}
.report-section h4 {
  margin-block: var(--space-3) var(--space-2);
}
.rating-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-block-end: var(--space-3);
}
.rating-label {
  font-weight: 600;
}
.rating-buttons {
  display: flex;
  gap: var(--space-2);
}
.rating-btn {
  flex: 1;
  min-block-size: var(--touch-min);
  min-inline-size: 0;
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  font-size: var(--text-lg);
  font-weight: 700;
  cursor: pointer;
}
.rating-btn.active {
  background: var(--color-secondary-soft);
  color: var(--color-secondary);
  border-color: var(--color-secondary);
}
.rating-captions {
  display: flex;
  justify-content: space-between;
  font-size: var(--text-sm);
}
.daily-report-form textarea,
.incident-form textarea,
.summary-card textarea,
.client-file textarea {
  inline-size: 100%;
  padding: var(--space-3);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  resize: vertical;
}
.daily-report-form .report-section textarea {
  margin-block-start: var(--space-2);
}
.not-medical-note {
  margin: 0 0 var(--space-3);
  padding-inline-start: var(--space-3);
  border-inline-start: 4px solid var(--color-warning);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}
.feeling-segment .cat-tab {
  min-block-size: var(--touch-min);
}
.dialog-wide {
  max-inline-size: 40rem;
}
.incident-form .field span:first-child {
  font-weight: 600;
}
.incident-form .field input[type="number"] {
  max-inline-size: 8rem;
}
.report-details summary {
  cursor: pointer;
  font-size: var(--text-base);
  line-height: 1.6;
  /* A finger-sized row to open a report (caregiver minimum, 44px). Padding,
     not display:flex — flex would drop the disclosure triangle. */
  padding-block: var(--space-2);
}
.report-body p {
  margin-block: var(--space-1);
}
/* partner organizations (modules/partners/) */
.partners-block {
  margin-block-start: var(--space-3);
}
.partner-links {
  margin-block: var(--space-2);
}
.partner-links .checkbox {
  gap: var(--space-1);
  margin-block-end: 0;
}
/* .field-inline stretches its inputs to 200px+ — not these checkboxes */
.partner-links input[type="checkbox"] {
  flex: none;
  min-inline-size: 0;
  padding: 0;
}
.partner-client h2 {
  margin-block: 0 var(--space-2);
}

/* "איך היה היום" — the day's headline in the client file */
.day-note-card .day-note {
  font-size: var(--text-lg);
  line-height: 1.6;
  margin-block: var(--space-1);
  white-space: pre-line;
}
.report-body .day-note {
  font-weight: 500;
}
.author-chip {
  font-weight: 600;
}
.snapshot-strip {
  line-height: 1.8;
}
.home-card {
  border-inline-start: 4px solid var(--color-secondary);
}
.summary-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.summary-head h3 {
  margin: 0;
}
.summary-text {
  white-space: pre-wrap;
}
.ai-badge {
  background: var(--color-secondary-soft);
  color: var(--color-secondary);
}
.file-quick-action {
  display: inline-block;
  inline-size: auto;
  padding-inline: var(--space-4);
}

.print-only {
  display: none;
}
.chart-grid {
  stroke: var(--color-border);
  stroke-width: 1;
}
.chart-line {
  fill: none;
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.chart-section h3 {
  margin-block: var(--space-4) var(--space-2);
}
.op-table tr.row-link {
  cursor: pointer;
}
.op-table tr.row-link:hover,
.op-table tr.row-link:focus-within,
.op-table tr.row-link:hover td:first-child,
.op-table tr.row-link:focus-within td:first-child {
  background: var(--color-surface-sunken);
}
/* The whole row is the tap target (onclick on the <tr>) — tall enough for
   a finger. A cell's block-size acts as a minimum. */
.op-table tr.row-link td {
  block-size: var(--touch-min-caregiver, 44px);
}

/* The org overview's all-clients table on a phone (dataTable's `stack`):
   one card per client — the name as the card's title, then "header: value"
   lines. The header row stays as a wrapping row of sort buttons. */
@media (max-width: 599px) {
  .op-table-stack,
  .op-table-stack thead,
  .op-table-stack tbody,
  .op-table-stack tr,
  .op-table-stack td {
    display: block;
  }
  .op-table-stack thead tr {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-block-end: var(--space-3);
  }
  .op-table-stack th,
  .op-table-stack th:first-child {
    position: static;
    padding: 0;
    border: none;
    background: none;
  }
  .op-table-stack .th-sort {
    min-block-size: var(--touch-min-caregiver, 44px);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    background: var(--table-bg, var(--color-bg));
  }
  /* Two "header: value" pairs per line when they fit, one at large text. */
  .op-table-stack tbody tr {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(9.5rem, 100%), 1fr));
    column-gap: var(--space-4);
    padding: var(--space-3);
    margin-block-end: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--table-bg, var(--color-bg));
  }
  .op-table-stack td,
  .op-table-stack td:first-child {
    position: static;
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    block-size: auto;
    padding: var(--space-1) 0;
    border: none;
    white-space: normal;
    overflow-wrap: anywhere;
    background: none;
    box-shadow: none;
  }
  .op-table-stack td::before {
    content: attr(data-label);
    color: var(--color-text-muted);
    font-weight: 600;
  }
  .op-table-stack td:first-child {
    grid-column: 1 / -1;
    font-size: var(--text-base);
    font-weight: 700;
  }
  .op-table-stack td:first-child::before {
    content: none;
  }
  .op-table-stack .row-open {
    min-block-size: var(--touch-min-caregiver, 44px);
    inline-size: 100%;
    max-inline-size: none;
  }
}
.op-table .row-open {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--color-primary);
  text-decoration: underline;
  text-align: start;
  cursor: pointer;
}
.report-title h2 {
  margin-block: var(--space-2) 0;
}

.insights-chat .chat-log {
  /* dvh, not vh: mobile vh is the tallest viewport (toolbars hidden), which
     would push the question box off the bottom. */
  max-block-size: min(60dvh, 40rem);
}
.insight-summary {
  margin-block-start: var(--space-2);
  padding-block-start: var(--space-2);
  border-block-start: 1px solid var(--color-border);
}
.insight-summary h4 {
  margin: 0 0 var(--space-1);
}
.insight-summary ul {
  margin: 0 0 var(--space-2);
  padding-inline-start: var(--space-4);
}
.insight-save {
  margin-block-start: var(--space-2);
}
.chat-msg.bot {
  max-inline-size: 95%;
}
.data-used {
  font-size: var(--text-sm);
}

/* Editable daily-report form (modules/reports/form-builder.js) */
.form-builder .base-row {
  gap: var(--space-3);
}
.form-builder .base-row input[type="text"] {
  flex: 1;
  min-inline-size: min(160px, 100%);
  padding: var(--space-2);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
}
.form-builder .question-form .field input,
.form-builder .question-form .field select,
.form-builder .question-form .field-inline input {
  padding: var(--space-2);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
}
.question-summary {
  font-size: var(--text-sm);
  font-weight: 400;
}
.form-preview {
  opacity: 0.92;
}
.question-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-block-end: var(--space-4);
}
.question-block input[type="number"],
.question-block input[type="time"] {
  padding: var(--space-3);
  font-size: var(--text-lg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  min-block-size: var(--touch-min);
}
.question-block .number-input {
  max-inline-size: 10rem;
}
.choice-chips .chip {
  min-block-size: var(--touch-min);
}
.custom-answer {
  margin-block: var(--space-1);
}

/* Guide's "דוחות יומיים" (modules/reports/guide-daily.js) */
.guide-daily-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  inline-size: 100%;
  min-block-size: var(--touch-min);
  margin-block-end: var(--space-4);
  font-size: var(--text-lg);
}
.guide-daily-row {
  inline-size: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: var(--touch-min);
  text-align: start;
  cursor: pointer;
  background: var(--color-surface);
  font: inherit;
  color: inherit;
}
.guide-daily-row .editor-card-label {
  flex: 1;
}
.report-status {
  font-size: var(--text-sm);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.report-status.done {
  border: 1px solid var(--color-success);
  color: var(--color-text);
}
.report-status.todo {
  background: var(--color-primary-soft);
  color: var(--color-text);
}
.report-status.guide {
  border: 1px dashed var(--color-success);
  color: var(--color-text);
}

/* The daily report's pass over the day's schedule + tasks
   (modules/reports/activity-review.js). */
.review-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.review-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2);
  border: 2px solid transparent;
  border-radius: var(--radius-md);
}
.review-row.review-missing {
  border-color: var(--color-danger);
}
.review-visual {
  inline-size: 48px;
  block-size: 48px;
  object-fit: contain;
  flex: none;
}
.review-visual-text {
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  background: var(--color-primary-soft);
  font-weight: 700;
}
.review-title {
  flex: 1;
  min-inline-size: 8rem;
  font-weight: 600;
}
.review-decision {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.review-choice .cat-tab {
  min-block-size: var(--touch-min);
  white-space: nowrap;
}
/* A decided row changes colour in place — nothing appears, wraps or moves. */
.review-row.review-done {
  background: color-mix(in srgb, var(--color-success) 22%, var(--color-surface));
  border-color: var(--color-success);
}
.review-row.review-not-done {
  background: color-mix(in srgb, var(--color-warning) 20%, var(--color-surface));
  border-color: var(--color-warning);
}

/* A parent's personal link (views/parent-link.js) and the staff side
   (views/dashboard.js createParentLink / parentLine). */
.pin-card .muted {
  white-space: pre-line;
}
.parent-invite h4 {
  margin-block: var(--space-4) var(--space-1);
}
.parent-email-invite {
  margin-block-start: var(--space-2);
}
.parent-email-invite summary {
  cursor: pointer;
  display: inline-block;
}
.parent-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-block: var(--space-2);
}
.link-box {
  inline-size: 100%;
  padding: var(--space-3);
  font-size: var(--text-sm);
  direction: ltr;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
}
.checklist {
  display: grid;
  gap: var(--space-2);
  margin-block: var(--space-3);
}

.chart-sub {
  margin-block: calc(-1 * var(--space-2)) var(--space-2);
  font-size: var(--text-sm);
}

/* Monthly professional reports (modules/professions/*) */
.prof-banner.late {
  border-color: var(--color-danger, #c0392b);
}
.prof-banner summary {
  cursor: pointer;
  font-weight: 700;
}
.prof-table {
  display: grid;
  gap: var(--space-1);
  overflow-x: auto;
}
/* The name column stays in view while the indicators scroll (same frame
   and --table-bg as the data tables above). */
.prof-row > :first-child {
  position: sticky;
  inset-inline-start: 0;
  z-index: 1;
  align-self: stretch;
  display: flex;
  align-items: center;
  padding-inline-end: var(--space-2);
  background: var(--color-surface);
  overflow-wrap: anywhere;
}
.prof-head > :first-child {
  background: var(--table-bg, var(--color-bg));
}
.scroll-hint[data-more-start] .prof-row > :first-child {
  box-shadow: -6px 0 6px -4px var(--edge-shade);
}
.prof-row {
  display: grid;
  /* --prof-cols = number of indicators (set by screen.js) */
  grid-template-columns: minmax(8rem, 2fr) repeat(var(--prof-cols, 3), minmax(5rem, 1fr)) minmax(5.5rem, auto);
  min-inline-size: calc(14rem + var(--prof-cols, 3) * 5.5rem);
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
  padding-inline: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  font: inherit;
  color: inherit;
  text-align: start;
}
button.prof-row {
  cursor: pointer;
}
.prof-head {
  font-weight: 700;
  font-size: var(--text-sm);
  background: transparent;
  border: none;
}
.prof-row.worse-row {
  border-inline-start: 4px solid var(--color-danger, #c0392b);
}
.trend.better {
  color: var(--color-success);
}
.trend.worse {
  color: var(--color-danger, #c0392b);
}
.prof-editor textarea,
.prof-editor input[type="text"] {
  inline-size: 100%;
}

/* --- "שליחה להורים" (parent-gifts.js) + the parent's gallery (parent-gallery.js) --- */
.gift-send-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 60px;
  white-space: nowrap;
}
.paint-footer .gift-send-wrap {
  margin-inline-start: auto;
}
/* The button plus, for an org client with no parent linked yet, a short
   line under it saying so (the button is then disabled, not hidden). */
.gift-send-wrap {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
}
.gift-send-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.gift-no-parent {
  max-inline-size: 16rem;
  font-size: var(--text-sm);
  text-align: center;
}
.gift-no-parent[hidden] {
  display: none;
}
/* "שליחה" on each item of the child's lists (parent-gifts.js's
   sendFromListButton): under a painting tile, beside a note card. */
.paint-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.paint-item .paint-thumb-card {
  flex: 1;
}
.note-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.note-item .note-card {
  flex: 1 1 14rem;
}
.gift-list-send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
  min-inline-size: var(--touch-min);
  padding-inline: var(--space-4);
  border: 2px solid var(--color-primary);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-primary);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.gift-list-send[hidden] {
  display: none;
}
.gift-list-send:disabled {
  opacity: 0.6;
}
.gift-sent {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: rgba(0, 0, 0, 0.35);
}
.gift-sent .celebration-state {
  background: var(--color-surface);
  border: 2px solid var(--color-primary);
  box-shadow: var(--shadow-2);
  max-inline-size: 26.25rem;
}
.gift-sent .celebration-icon {
  color: var(--color-danger);
}
.gift-sent-anim .celebration-state {
  animation: gift-pop 320ms ease-out;
}
@keyframes gift-pop {
  from {
    transform: scale(0.85);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

.gift-gallery {
  margin-block: var(--space-4);
}
.gift-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-3);
}
.gift-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  text-align: start;
  cursor: pointer;
  min-inline-size: 0;
}
.gift-thumb,
.gift-note-preview {
  inline-size: 100%;
  aspect-ratio: 1;
  border-radius: var(--radius-md);
  background: #ffffff;
}
.gift-thumb {
  object-fit: contain;
}
.gift-note-preview {
  overflow: hidden;
  padding: var(--space-2);
  color: #222222;
  font-size: var(--text-sm);
  line-height: 1.5;
  white-space: pre-line;
}
.gift-title {
  font-weight: var(--font-weight-heading);
  /* wraps, never an ellipsis — a long title stays readable at 200% text */
  overflow-wrap: anywhere;
}
.gift-when {
  font-size: var(--text-sm);
}
.gift-new {
  position: absolute;
  z-index: 1;
  /* the far corner — a note's text starts at inline-start */
  inset-block-start: var(--space-3);
  inset-inline-end: var(--space-3);
  padding: 2px var(--space-2);
  border-radius: 999px;
  background: var(--color-primary);
  color: var(--color-primary-contrast);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-heading);
}
.gift-dialog {
  inline-size: min(92vw, 720px);
}
.gift-full-img {
  display: block;
  inline-size: 100%;
  max-block-size: 70dvh;
  object-fit: contain;
  background: #ffffff;
  border-radius: var(--radius-md);
}
.gift-full-note {
  min-block-size: 0;
  max-block-size: 60dvh;
  overflow: auto;
}
@media (max-width: 480px) {
  .gift-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Profession screen: the unit chips (all three tabs) + charts/chat tabs */
.prof-unit-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  margin-block: var(--space-2, 0.5rem);
}
.prof-client-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  margin-block: var(--space-2, 0.5rem);
}
.prof-client-tools input[type="search"] {
  flex: 1 1 14rem;
  min-inline-size: 0;
  min-block-size: var(--touch-min-caregiver, 44px);
}
.prof-charts {
  display: grid;
  gap: var(--space-4, 1rem);
}
.prof-details {
  margin-block: var(--space-4, 1rem);
}
.prof-details > summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 1.1rem;
  min-block-size: 44px;
  display: flex;
  align-items: center;
}
.insight-summary .use-summary {
  margin-block-start: var(--space-2, 0.5rem);
}

/* ---------------------------------------------- Accessibility menu (נגישות)
   js/a11y-menu.js. The menu's own controls are all >= 60px so it's usable by
   the people who need it most — including a child, when the caregiver shows
   the button on the home screen. */
.a11y-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  white-space: nowrap;
}
.auth-card-head,
.pin-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.pin-card-head h1 {
  flex: 1;
}
.home-head-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.a11y-menu .field {
  margin-block: var(--space-3);
}
.a11y-sizes {
  flex-wrap: wrap;
}
.a11y-sizes .a11y-size {
  flex: 1 1 auto;
  min-block-size: var(--touch-min);
  white-space: nowrap;
}
.a11y-switch {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: var(--touch-min);
  padding-block: var(--space-2);
  border-block-start: 1px solid var(--color-border);
  cursor: pointer;
}
.a11y-switch input {
  flex: none;
  inline-size: 28px;
  block-size: 28px;
  accent-color: var(--color-primary);
}
.a11y-switch-text {
  display: flex;
  flex-direction: column;
  font-weight: 600;
}
.a11y-switch-text small {
  font-weight: 400;
}

/* The live password rule list (js/password-rules.js). */
.password-rules {
  list-style: none;
  padding: 0;
  margin: calc(-1 * var(--space-2)) 0 var(--space-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.password-rules li::before {
  content: "○";
  margin-inline-end: var(--space-1);
}
.password-rules li[data-ok="true"] {
  color: var(--color-success-ink);
}
.password-rules li[data-ok="true"]::before {
  content: "✓";
}

/* A masked phone number (050-•••-4321) never breaks across lines. */
.phone-hint {
  white-space: nowrap;
}

/* The long-wait overlay (js/wait-overlay.js): after 5s of waiting on the
   server, a centered, blocking panel. A stronger dim than other dialogs, but
   no backdrop blur — docs/design.md §3 rules glassmorphism out. */
.wait-overlay {
  max-inline-size: 22rem;
  align-items: center;
  text-align: center;
}
.wait-overlay::backdrop {
  background: rgb(0 0 0 / 0.55);
}
.wait-spinner {
  inline-size: 3.5rem;
  block-size: 3.5rem;
  border-width: 5px;
}
.wait-text {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0;
}
.wait-actions {
  justify-content: center;
}
[data-mode="user"] .wait-actions button {
  min-block-size: var(--touch-min);
  min-inline-size: 8rem;
}

/* ---- Phone in landscape (short screen) -----------------------------------
   An 844x390 phone gave the AAC grid ~200px of height under the nav bar and
   the sentence bar. On a short screen: a slimmer gutter and gaps, and the
   board puts the nav bar and the sentence bar side by side in one row (the
   title is visually hidden there — still the page's h1 for screen readers
   and the tab title). Targets stay at --touch-min: only padding and gaps
   shrink. */
@media (max-height: 480px) and (orientation: landscape) {
  #main {
    --main-pad: var(--space-2);
  }
  .aac-board:not(.aac-board-preview) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
  }
  .aac-board:not(.aac-board-preview):has(> .aac-breadcrumb) {
    grid-template-rows: auto auto minmax(0, 1fr);
  }
  .aac-board:not(.aac-board-preview) > :not(.nav-bar, .sentence-bar) {
    grid-column: 1 / -1;
  }
  .aac-board:not(.aac-board-preview) .nav-title {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .nav-bar {
    gap: var(--space-2);
  }
  .nav-btn {
    padding-inline: var(--space-2);
  }
  .sentence-bar {
    padding: var(--space-1);
    min-block-size: calc(var(--touch-min) + var(--space-1) * 2);
  }
  .cat-tabs {
    gap: var(--space-1);
  }
  .cat-tab {
    padding-inline: var(--space-3);
  }
}

/* קול ההקראה — the Hila/Avri choice (voice-picker.js), in the new-child
   forms and on a child's card. */
.voice-choice {
  border: 1px solid var(--color-border, currentColor);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem);
  margin-block: var(--space-2, 0.5rem);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2, 0.5rem) var(--space-4, 1rem);
}
.voice-choice legend {
  padding-inline: var(--space-1, 0.25rem);
  font-weight: 600;
}
.voice-option {
  display: flex;
  align-items: center;
  gap: var(--space-1, 0.25rem);
}
.voice-radio {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1, 0.25rem);
  min-block-size: 44px;
  cursor: pointer;
}
.voice-play {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  min-block-size: 44px;
  min-inline-size: 44px;
}
/* Inside an inline form row (the org "הוספת מטופל/ת" form is .field-inline)
   the picker takes its own full row, and its radios must not pick up
   .field-inline input's text-field sizing (flex:1, min 200px, padding) — that
   pushed each radio far from its name and split "הילה (קול אישה)" around the
   ▶ button. The name and its "(קול …)" stay on one line. */
.field-inline .voice-choice {
  flex-basis: 100%;
}
.voice-choice .voice-radio input[type="radio"] {
  flex: none;
  min-inline-size: 0;
  inline-size: auto;
  padding: 0;
  margin: 0;
}
.voice-radio > span {
  white-space: nowrap;
}

/* Insights chat period row (modules/reports/chat.js): chips, ‹ / › arrows,
   and the "בחירת תאריך" jump. */
.chat-period-date {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}
.chat-period .period-nav button:disabled {
  opacity: 0.4;
  cursor: default;
}

/* The partner quick report window (modules/partners/partners.js). */
.quick-report {
  inline-size: min(34rem, calc(100vw - 2rem));
  max-block-size: 92dvh;
  overflow-y: auto;
}
.quick-report .period-picker {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
}
.quick-report .period-picker .child-switch {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.quick-report .dialog-actions {
  position: sticky;
  inset-block-end: 0;
  background: var(--color-surface);
  padding-block: var(--space-2);
}
.quick-report-date {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.quick-report-clients {
  max-block-size: 32dvh;
  overflow-y: auto;
}
.file-partners:empty {
  display: none;
}

/* The "show password" eye (js/password-toggle.js). */
.password-wrap {
  position: relative;
}
.password-wrap input {
  inline-size: 100%;
  padding-inline-end: calc(var(--touch-min-caregiver) + var(--space-1));
}
.password-toggle {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: var(--touch-min-caregiver);
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  color: var(--color-text-muted, currentColor);
  cursor: pointer;
}
.password-toggle:focus-visible {
  outline: 3px solid var(--color-focus, currentColor);
  outline-offset: -3px;
}

/* --- the org parent's page (reports/parent.js): the week's good moments ---
   Each line takes one of the AAC word-type colours (--pos-*, tokens.css),
   which already have lightened dark-theme values. */
.parent-highlights {
  border-block-start: 6px solid var(--pos-pronoun);
  background: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--pos-pronoun) 10%, var(--color-surface)),
    var(--color-surface) 120px
  );
}
.parent-highlights h2 {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: 0;
}
.highlight-title-icon {
  display: inline-flex;
  color: var(--pos-noun);
}
.highlight-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-3);
}
.highlight-list li {
  --tile: var(--color-secondary);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: color-mix(in srgb, var(--tile) 15%, var(--color-surface));
  border: 2px solid color-mix(in srgb, var(--tile) 45%, var(--color-surface));
  border-radius: var(--radius-md);
  font-size: var(--text-lg);
  font-weight: 600;
}
.highlight-list li[data-kind="tasks"] { --tile: var(--pos-verb); }
.highlight-list li[data-kind="schedule"] { --tile: var(--pos-adjective); }
.highlight-list li[data-kind="tokens"] { --tile: var(--pos-pronoun); }
.highlight-list li[data-kind="reading"] { --tile: var(--pos-question); }
.highlight-list li[data-kind="writing"] { --tile: var(--pos-social); }
.highlight-list li[data-kind="paintings"] { --tile: var(--pos-noun); }
.highlight-list li[data-kind="notes"] { --tile: var(--color-secondary); }
.highlight-icon {
  flex: none;
  display: inline-grid;
  place-items: center;
  inline-size: 48px;
  block-size: 48px;
  border-radius: 50%;
  background: var(--tile);
  color: var(--color-surface);
}
.parent-more summary {
  font-weight: 600;
}

/* --- AAC editor: top-level folder count + the folder library (folder-library.js) --- */
.add-cat {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.add-cat input {
  flex: 1 1 14rem;
}
.add-cat-count {
  font-size: var(--text-sm);
}
.folder-lib-search {
  inline-size: 100%;
  margin-block: var(--space-2);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  color: var(--color-text);
}
.folder-lib-groups {
  flex-wrap: wrap;
}
.folder-lib-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: var(--space-2);
  margin-block: var(--space-3);
}
.folder-lib-tile {
  display: flex;
  flex-direction: column;
  border: 2px solid var(--cat-color, var(--color-border));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--cat-color, transparent) 8%, var(--color-surface));
}
.folder-lib-pick {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  min-block-size: 60px;
  padding: var(--space-2);
  text-align: center;
  cursor: pointer;
}
.folder-lib-pick input {
  position: absolute;
  inset-block-start: var(--space-2);
  inset-inline-start: var(--space-2);
  inline-size: 1.4rem;
  block-size: 1.4rem;
}
.folder-lib-pick img {
  inline-size: 3.5rem;
  block-size: 3.5rem;
  object-fit: contain;
}
.folder-lib-name {
  font-weight: 600;
}
.folder-lib-meta {
  font-size: var(--text-sm);
}
.folder-lib-peek {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-block-size: 44px;
  border-block-start: 1px solid color-mix(in srgb, var(--cat-color, var(--color-border)) 40%, transparent);
  font-size: var(--text-sm);
}
.folder-lib-tile:has(input:checked) {
  box-shadow: 0 0 0 3px var(--cat-color, var(--color-primary));
}
.folder-lib-tile.on-board .folder-lib-pick {
  cursor: default;
  opacity: 0.7;
}
.folder-lib-pick:has(input:focus-visible) {
  outline: 3px solid var(--color-focus, var(--color-primary));
  outline-offset: 2px;
}
.folder-lib-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.folder-preview-icon {
  inline-size: 2.5rem;
  block-size: 2.5rem;
  object-fit: contain;
}
.folder-preview-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
  gap: var(--space-2);
  max-block-size: 50vh;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}
.folder-preview-cards li {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  text-align: center;
  font-size: var(--text-sm);
}
.folder-preview-cards img {
  inline-size: 3rem;
  block-size: 3rem;
  object-fit: contain;
}

/* The boot guard's fallback screen (js/boot-guard.js): shown inside #main.boot
   when the app could not start. Built without ui.js, so plain elements. */
.boot-help {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  max-inline-size: 32rem;
  padding: var(--space-4);
  text-align: center;
}
.boot-help button {
  min-block-size: var(--touch-min);
  min-inline-size: 12rem;
}

/* --- the overview's attention list (reports/overview.js attentionCard) --- */
.attention-list {
  list-style: none;
  margin: 0 0 var(--space-2);
  padding: 0;
  display: grid;
  gap: var(--space-2);
}
.attention-row {
  inline-size: 100%;
  min-block-size: var(--touch-min-caregiver);
  display: grid;
  grid-template-columns: minmax(8rem, 14rem) minmax(7rem, 10rem) 1fr;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-inline-start: 4px solid var(--color-danger, #c0392b);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: inherit;
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.attention-row:hover {
  background: var(--color-surface-sunken);
}
.attention-who {
  display: grid;
}
.attention-count {
  font-weight: 600;
}
.attention-areas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
}
.attention-area {
  white-space: nowrap;
}
@media (max-width: 600px) {
  .attention-row {
    grid-template-columns: 1fr;
  }
}

/* --- the overview's unit comparison (reports/overview.js compareCard) --- */
.compare-units {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
}
.compare-units legend {
  padding: 0;
  margin-block-end: var(--space-2);
  font-weight: 600;
}
.compare-unit {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min-caregiver);
  cursor: pointer;
}
.compare-unit input {
  inline-size: 20px;
  block-size: 20px;
  accent-color: var(--color-primary);
}
.compare-units p {
  flex-basis: 100%;
  margin: 0;
}
.compare-charts {
  display: grid;
  gap: var(--space-5);
  margin-block-start: var(--space-3);
}
.compare-charts h4 {
  margin: 0 0 var(--space-2);
}
/* The row label carries the unit's name and, for counts, its total. */
.compare-card .hbars li {
  grid-template-columns: minmax(7rem, 16rem) 1fr auto;
}
@media (max-width: 600px) {
  .compare-card .hbars li {
    grid-template-columns: 1fr auto;
  }
}
