:root {
  /* Dark theme (default/floor) — DesignSync-approved "terracotta-clay" palette (Issue #48/T003). */
  --bg: #1a1912;
  --panel: #252419;
  --border: #767454;
  --fg: #eef0e2;
  --muted: #a7a891;
  --accent: #c98a4d;
  --on-accent: #1a1912;

  --info-fg: #8fc1e0;
  --info-border: #4a90b8;
  --info-fill: rgba(74, 144, 184, 0.16);

  --warn-fg: #e8b84b;
  --warn-border: #a67a1f;
  --warn-fill: rgba(166, 122, 31, 0.16);

  --error-fg: #e88a73;
  --error-border: #b8543a;
  --error-fill: rgba(184, 84, 58, 0.16);

  --sync-synced: #7bbf6e;
  --sync-pending: #d9a441;

  /* Type scale (theme-invariant — shared by both themes via :root's cascade). */
  --font-h1: 1.375rem;
  --font-h2: 1.1rem;
  --font-body: 1rem;
  --font-small: 0.8125rem;
  --line-body: 1.55;
  --weight-normal: 400;
  --weight-strong: 700;

  /* Spacing scale (theme-invariant). */
  --space-3xs: 0.125rem;
  --space-2xs: 0.25rem;
  --space-xs: 0.375rem;
  --space-sm: 0.5rem;
  --space-md: 0.75rem;
  --space-lg: 1.25rem;

  /* Elevation / border radii (theme-invariant). */
  --radius-sm: 0.375rem;
  --radius-md: 0.625rem;
  --elev-chrome: 0 1px 0 rgba(0, 0, 0, 0.35);
  --elev-panel: 0 1px 3px rgba(0, 0, 0, 0.22);
  --elev-overlay: 0 6px 16px rgba(0, 0, 0, 0.35);

  color-scheme: dark;
}

/* Light theme override — DesignSync-approved "terracotta-clay" palette (Issue #48/T003).
   Only colour-token values differ from :root's dark default; no component rule gets a
   light/dark-specific override (FR-007). :root stays dark so no-preference/unsupported
   browsers fall back to dark for free (FR-008). */
@media (prefers-color-scheme: light) {
  :root {
    color-scheme: light;

    --bg: #f2efe2;
    --panel: #fbfaf3;
    --border: #82806a;
    --fg: #262418;
    --muted: #6a6952;
    --accent: #8a4f26;
    --on-accent: #fbfaf3;

    --info-fg: #1f5c82;
    --info-border: #3d80a8;
    --info-fill: rgba(61, 128, 168, 0.12);

    --warn-fg: #7a5a10;
    --warn-border: #a67a1f;
    --warn-fill: rgba(166, 122, 31, 0.14);

    --error-fg: #8c3a24;
    --error-border: #b8543a;
    --error-fill: rgba(184, 84, 58, 0.12);

    --sync-synced: #3f7a35;
    --sync-pending: #8a6218;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--fg);
}

/* Focus visibility (Issue #48 DesignSync approval, T003 gate — "Proposed (#48)" card,
   design/components/inputs.html as of commit 7cd1818/602b928): every focusable element gets a
   solid accent-coloured outline rather than relying on a colour-only cue, so keyboard focus stays
   visible without depending on colour discrimination alone. Deliberately global/unscoped — not
   itemised per input/button/select class — so a future interactive control needs no opt-in to
   inherit it. */
:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.app-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  max-width: 60rem;
  margin: 0 auto;
  padding: 1rem;
}

.app-header {
  border-bottom: 1px solid var(--border);
  box-shadow: var(--elev-chrome);
  padding-bottom: var(--space-md);
}

.app-header h1 {
  margin: 0;
  font-size: var(--font-h1);
}

/* Section-heading scale step (Issue #48/T003 DesignSync "Proposed" card, design/foundations/
   type.html) — applied to every real <h2>/<h3> that introduces a page section, so headings
   render at the designed 1.1rem/700 "stamped" treatment instead of the browser default. Not a
   bare element selector (`h2 { ... }`) because some `<h2>`/`<h3>` nest inside cards/subsections
   at a deliberately smaller visual tier (e.g. Events' "Task templates", the daily schedule's
   "Swapped out today") and should not inherit this top-level scale — see 048-design-foundations
   bugfix diagnosis for the explicit list this class was applied to. */
.section-heading {
  font-size: var(--font-h2);
  font-weight: var(--weight-strong);
}

.tagline {
  margin: var(--space-2xs) 0 0;
  color: var(--muted);
}

.app-body {
  flex: 1;
  padding-top: 1rem;
}

/* Issue #48 Phase 7: restyled to the approved DesignSync "Proposed (#48)" tokens — an italic tone
   plus a real, subtly-filled/rounded box (`--bg`/`--radius-md`/`--space-md`), not the bare
   colour-only conversion this rule shipped as before. The `.placeholder[role='alert']` rule
   immediately below is additive alongside this one — it still layers its own
   `border`/`background`/`padding` on top unchanged for the top-level error case. */
.placeholder {
  color: var(--muted);
  font-style: italic;
  padding: var(--space-md);
  background: var(--bg);
  border-radius: var(--radius-md);
}

/* US4/FR-015/FR-016 (Issue #48 Phase 7): `.placeholder` covers both a plain loading state (no
   role) and a top-level error (`role="alert"`, app.rs:436) — distinguish the two without renaming
   or splitting the class, by adding a more specific rule keyed on the structural `role="alert"`
   attribute that's already present at the error site. Reuses the same `--error-*` triplet the
   notice/banner pattern above uses, so the two error treatments read consistently. This rule is
   additive alongside the base `.placeholder` rule above — it never rewrites it. */
.placeholder[role='alert'] {
  color: var(--error-fg);
  border: 1px solid var(--error-border);
  border-radius: var(--radius-md);
  background: var(--error-fill);
  padding: var(--space-sm) var(--space-md);
}

/* Shared notice/banner pattern (FR-012/FR-013, Issue #48 Phase 3 — the only CSS these four classes
   get in this feature; no later task restyles them). One shared layout/border/padding/typography
   treatment across all three severities, each severity resolving its own fg/border/fill from its
   own --info-* / --warn-* / --error-* triplet (T004/T005 — already declared and DesignSync-approved
   in both themes, so this pattern is correct in both the moment it lands). A non-colour severity cue
   (.notice-icon + .notice-severity-label, T009's markup) always accompanies colour, so severity is
   never conveyed by colour alone (FR-009/FR-012). */
.storage-warning,
.sign-in-notice,
.repair-notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  margin: var(--space-md) 0 0;
  padding: var(--space-sm) var(--space-md);
  border: 1px solid;
  border-radius: var(--radius-md);
  box-shadow: var(--elev-overlay);
  font-size: var(--font-small);
  line-height: var(--line-body);
}

.storage-warning {
  color: var(--warn-fg);
  border-color: var(--warn-border);
  background: var(--warn-fill);
}

.sign-in-notice {
  color: var(--error-fg);
  border-color: var(--error-border);
  background: var(--error-fill);
}

/* TD007/Issue #51 (T039, preserved verbatim by FR-014): informational, not a warning/error — a
   repair the client already made on the member's behalf, hence the info triplet rather than
   `.storage-warning`'s warn or `.sign-in-notice`'s error. `flex: 1 1 100%` forces it onto its own
   full-width row inside `.workspace-header`'s flex-wrap layout (`:115`), so it can never end up
   sharing a row with — and so squeezing or overlapping — the sync indicator or sign-out button at a
   narrow (375px) viewport; this is the same non-regression guarantee the pre-pattern CSS carried,
   unchanged by this shared-pattern rewrite. */
.repair-notice {
  flex: 1 1 100%;
  color: var(--info-fg);
  border-color: var(--info-border);
  background: var(--info-fill);
}

/* The wrapper `<span>` around each notice's severity label + message text (T009's markup) is
   always the second child, right after `.notice-icon` — grow it to fill the row so a trailing
   element (only `.repair-notice-dismiss` has one) is pushed flush to the end with no
   `justify-content` needed. */
.storage-warning > span:nth-child(2),
.sign-in-notice > span:nth-child(2),
.repair-notice > span:nth-child(2) {
  flex: 1 1 auto;
  min-width: 0;
}

.notice-icon {
  flex: 0 0 auto;
  font-weight: var(--weight-strong);
  line-height: var(--line-body);
}

.notice-severity-label {
  display: block;
  margin-bottom: var(--space-3xs);
  font-size: 0.7rem;
  font-weight: var(--weight-strong);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.repair-notice-dismiss {
  flex: 0 0 auto;
  width: 1.75rem;
  height: 1.75rem;
  font-size: var(--font-small);
  line-height: 1;
  color: inherit;
  background: transparent;
  border: 1px solid currentColor;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.repair-notice-dismiss:hover {
  background: var(--info-border);
}

.roundtrip {
  display: flex;
  gap: var(--space-sm);
  margin-top: 1rem;
  flex-wrap: wrap;
}

.roundtrip-input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: 0.6rem var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.roundtrip-button {
  padding: 0.6rem 1rem;
  font-size: var(--font-body);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.roundtrip-button:disabled {
  opacity: 0.6;
  cursor: progress;
}

.roundtrip-result {
  margin-top: var(--space-md);
  min-height: 1.25rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Entry surface (Issue #48/#155/T021): `CreateHome` is a root-level state render — the same
   relationship `.sign-in` (:399) has to the signed-out state — so it takes `.sign-in`'s flex-column
   shape rather than `.rooms`/`.events`/`.home-panel`'s nested-panel `margin-top: 1rem`. Its own
   `.roundtrip` form is already fully styled above. `.create-home-error` gets only the base
   error-text colour, matching the `.home-panel-error`/`.room-create-error`/`.chore-create-error`
   precedent, not the full `.storage-warning`-style banner — that adoption is deferred to Issue
   #155, per this feature's own Assumptions. */
.create-home {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.create-home-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.workspace-header {
  display: flex;
  gap: var(--space-sm) 1rem;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
}

.sync-indicator {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
  white-space: nowrap;
}

.sync-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: currentColor;
}

.sync-indicator.synced {
  color: var(--sync-synced);
}

.sync-indicator.pending {
  color: var(--sync-pending);
}

.sync-indicator.offline {
  color: var(--muted);
}

.sync-indicator.offline-pending {
  color: var(--sync-pending);
}

.item-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.item-row {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
}

.item-label {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.item-delete {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  font-size: var(--font-body);
  color: var(--error-fg);
  font-weight: var(--weight-strong);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.item-delete:hover {
  border-color: var(--error-border);
}

.identity-capture h2 {
  margin: 0 0 0.25rem;
}

/* Desktop bulk-management view gets more breathing room. */
@media (min-width: 48rem) {
  .app-shell {
    padding: 2rem;
  }

  .app-header h1 {
    font-size: 1.75rem;
  }
}

.view-toggle {
  display: flex;
  gap: var(--space-sm);
  align-items: center;
}

.view-toggle-button {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.view-toggle-button:hover {
  background: var(--panel);
}

.view-toggle-button.active {
  color: var(--on-accent);
  background: var(--accent);
  border-color: var(--accent);
}

.workspace {
  display: flex;
  flex-direction: column;
}

.workspace-preparing {
  color: var(--muted);
  font-size: var(--font-small);
  margin: var(--space-md) 0 0;
}

.sign-in {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.sign-out {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.sign-out:hover {
  background: var(--border);
}

/* Chore tags: chips whose label doubles as a tap-to-edit control, plus a remove ✕. */
.chore-tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin: var(--space-2xs) 0;
  padding: 0;
}

.chore-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
  padding: var(--space-3xs) var(--space-xs);
}

/* The tag label is a button (tap to edit in place) but should read as plain text. */
.chore-tag-text {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: text;
}

.chore-tag-edit-input {
  font: inherit;
  padding: 0 var(--space-3xs);
  min-width: 4rem;
}

.chore-tag-remove {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  line-height: 1;
  color: var(--error-fg);
  font-weight: var(--weight-strong);
  cursor: pointer;
  opacity: 0.6;
}

.chore-tag-remove:hover {
  opacity: 1;
}

/* Inline "add a tag" affordance beneath the chip row. */
.chore-tag-add {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: var(--space-2xs) 0;
}

.chore-tag-input {
  flex: 1 1 8rem;
  min-width: 0;
  padding: var(--space-3xs) var(--space-xs);
  font-size: var(--font-small);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.chore-tag-add-button {
  padding: var(--space-3xs) var(--space-sm);
  font-size: var(--font-small);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.chore-tag-add-button:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* Comma-separated tags field in the chore-create form. Longest placeholder in the row ("Tags,
   comma-separated (optional)…"), so it gets the widest basis of the three (bug: input-sizing —
   this rule previously had no width/flex-grow at all, so under the file's global
   `box-sizing: border-box` its padding/border ate into the browser's fixed default text-input
   width instead of adding to it, clipping the placeholder — same idiom already used by
   `.chore-tag-input`/`.room-rename-input`/`.event-rename-input` below, `flex: <grow> <shrink>
   <basis>; min-width: 0;`, not a novel width strategy). */
.chore-tags-input {
  flex: 1 1 22rem;
  min-width: 0;
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

/* Chores surface (Issue #48/T016): the create form and each chore row's inline edit share one
   input/select treatment; `.chore-tag*` (T014) is untouched. Error paragraphs here get only the
   base error-text colour, not the full `.storage-warning`-style banner pattern — that distinction
   is deliberate and mirrored by later per-surface tasks. */
.chore-create,
.chore-edit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-top: 1rem;
}

/* The two free-text fields with a `placeholder` (bug: input-sizing) get their own explicit width
   strategy, split out of the shared block below — same idiom as `.chore-tags-input` above and
   `.room-rename-input`/`.event-rename-input` further down. The remaining shared-block members are
   all `<select>`/`<input type="date">`/`<input type="number">`: browsers already size a `<select>`
   to its selected option's content by default (confirmed: they render uncut with no width rule at
   all), so giving them the same `min-width: 0` would let them shrink *below* that content on a
   crowded row — a regression, not a fix — and is deliberately not done here. */
.chore-name-input,
.chore-notes-input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.chore-last-completed-input,
.chore-schedule-due-date,
.chore-schedule-week-interval,
.chore-schedule-day-of-month,
.chore-schedule-month-interval,
.chore-schedule-interval-days,
.chore-effort-input,
.chore-room-input,
.chore-urgency-input,
.chore-owner-input,
.chore-schedule-kind,
.chore-schedule-pattern-kind {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

/* The four numeric schedule sub-fields are short by nature (a day-of-month, an interval count) —
   narrower than the shared input/select width above. */
.chore-schedule-week-interval,
.chore-schedule-day-of-month,
.chore-schedule-month-interval,
.chore-schedule-interval-days {
  width: 4rem;
}

.chore-create-button {
  padding: 0.6rem 1rem;
  font-size: var(--font-body);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.chore-create-button:disabled {
  opacity: 0.6;
  cursor: progress;
}

.chore-create-error,
.chore-edit-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.chore-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.chore-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.chore-schedule-summary,
.chore-last-completed-summary,
.chore-room-summary,
.chore-events-summary {
  margin: 0;
  color: var(--muted);
  font-size: var(--font-small);
}

/* Schedule sub-field wrapper divs — the outermost `.chore-schedule` plus the recurring/monthly
   variants — lay their child controls out in one flex-wrap row; only the weekly variant stacks
   its weekday chips above its week-interval input. */
.chore-schedule,
.chore-schedule-recurring,
.chore-schedule-monthly {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
}

.chore-schedule-weekly {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.chore-schedule-weekdays,
.chore-events-input {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
}

.chore-event-checkbox {
  display: inline-flex;
  align-items: center;
}

.chore-claim-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.chore-claim,
.chore-last-completed-clear,
.chore-mark-done {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.chore-claim:hover,
.chore-last-completed-clear:hover,
.chore-mark-done:hover {
  background: var(--border);
}

.chore-claim:disabled,
.chore-last-completed-clear:disabled,
.chore-mark-done:disabled {
  opacity: 0.6;
  cursor: progress;
}

.chore-claimed-by {
  color: var(--muted);
  font-size: var(--font-small);
}

.chore-delete {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  font-size: var(--font-body);
  color: var(--error-fg);
  font-weight: var(--weight-strong);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.chore-delete:hover {
  border-color: var(--error-border);
}

.chore-delete:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* Issue #46/B048's completed-today log (T015): one row per live completion, plus its own summary
   line and empty state. Reuses `.item-list`/`.item-row`'s list rhythm and `.repair-notice`'s
   flex-wrap-to-own-line trick for the row error, rather than inventing a new layout pattern. No
   distinguishing/emphasis treatment beyond token conversion — that's US4's job (T026/T027). */
.capacity-completed-today {
  margin: var(--space-2xs) 0 0;
  color: var(--fg);
}

.completed-today-list {
  list-style: none;
  margin: var(--space-sm) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.completed-today-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.completed-today-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--font-body);
  color: var(--fg);
}

.completed-today-effort {
  flex: 0 0 auto;
  font-size: var(--font-small);
  color: var(--muted);
  white-space: nowrap;
}

.completed-today-undo {
  flex: 0 0 auto;
  padding: var(--space-3xs) var(--space-sm);
  font-size: var(--font-small);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.completed-today-undo:disabled {
  opacity: 0.6;
  cursor: progress;
}

.completed-today-row-error {
  flex: 1 1 100%;
  margin: 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

/* FR-015: genuinely restyled to the new tokens, not a bare colour/font-size conversion — an italic
   tone plus a real, subtly-filled/bordered box (the same `--panel`/`--border`/`--radius-md` plain
   panel-box treatment `.completed-today-item` already uses above, not the coloured/`box-shadow`
   notice/banner pattern at `:151-164`, since this is an informational empty state, not an alert) so
   an empty list still reads as "the app checked and there's nothing" rather than a layout accident,
   per the approved DesignSync proposal card. No class renamed. */
.completed-today-empty {
  margin: var(--space-sm) 0 0;
  padding: var(--space-md);
  color: var(--muted);
  font-size: var(--font-small);
  font-style: italic;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

/* Rooms surface (Issue #48/#162/T017): the create form and each room row's inline rename share
   the chore-create/chore-row shape (T016) — same input/button/list/row/delete tokens, no new
   pattern invented. Error paragraphs get only the base error-text colour, matching the
   chore-create-error/chore-edit-error precedent, not the full `.storage-warning`-style banner. */
.rooms {
  margin-top: 1rem;
}

.room-create {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-top: 1rem;
}

.room-name-input {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.room-create-button {
  padding: 0.6rem 1rem;
  font-size: var(--font-body);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.room-create-button:disabled {
  opacity: 0.6;
  cursor: progress;
}

.room-create-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.room-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* Each row lays its rename input, delete button and either error out in a flex-wrap line — an
   error paragraph takes `flex: 1 1 100%` to drop onto its own full-width line, the same trick
   `.repair-notice`/`.completed-today-row-error` already use. */
.room-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.room-rename-input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.room-rename-error,
.room-delete-error {
  flex: 1 1 100%;
  margin: 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.room-delete {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  font-size: var(--font-body);
  color: var(--error-fg);
  font-weight: var(--weight-strong);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.room-delete:hover {
  border-color: var(--error-border);
}

.room-delete:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* Browse-by-room surface (Issue #48/#162/T017): a read-only filter select plus a result list,
   mirroring `.item-list`/`.item-row`'s list rhythm — no per-row controls, so no delete/error
   treatment is needed here. */
.browse-by-room {
  margin-top: 1rem;
}

.browse-by-room-select {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.browse-by-room-items {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.browse-by-room-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.browse-by-room-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--font-body);
  color: var(--fg);
}

.browse-by-room-effort,
.browse-by-room-schedule {
  flex: 0 0 auto;
  font-size: var(--font-small);
  color: var(--muted);
  white-space: nowrap;
}

/* Events surface (Issue #48/#158/T018): the create form and each event row's inline rename/
   trigger/delete share the room-create/room-row shape (T017) — same input/button/list/row/delete
   tokens, no new pattern invented. `.event-trigger` is a secondary toggle button (mirrors
   `.sign-out`/`.chore-claim`, not the accent-filled create/submit treatment), `.event-status` is
   muted summary text, and error paragraphs get only the base error-text colour, matching the
   room-rename-error/room-delete-error precedent, not the full `.storage-warning`-style banner. */
.events {
  margin-top: 1rem;
}

.event-create {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-top: 1rem;
}

.event-name-input {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.event-create-button {
  padding: 0.6rem 1rem;
  font-size: var(--font-body);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.event-create-button:disabled {
  opacity: 0.6;
  cursor: progress;
}

.event-create-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.event-list {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* Each row lays its rename input, trigger toggle, status, delete button, and any error out in a
   flex-wrap line; the nested `.task-templates` block (below) drops to its own full-width line
   beneath them (`flex: 1 1 100%`, the same trick `.repair-notice`/error paragraphs already use). */
.event-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.event-rename-input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.event-rename-error,
.event-trigger-error,
.event-delete-error {
  flex: 1 1 100%;
  margin: 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.event-trigger {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.event-trigger:hover {
  background: var(--border);
}

.event-trigger:disabled {
  opacity: 0.6;
  cursor: progress;
}

.event-status {
  color: var(--muted);
  font-size: var(--font-small);
}

.event-delete {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  font-size: var(--font-body);
  color: var(--error-fg);
  font-weight: var(--weight-strong);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.event-delete:hover {
  border-color: var(--error-border);
}

.event-delete:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* Per-event task templates (Issue #48/#158/T018, US8/FR-030): a nested create form + list, same
   shape as `.event-create`/`.event-list`/`.event-row` one level down. `.task-templates` drops to
   its own full-width line inside the flex-wrap `.event-row` above it. */
.task-templates {
  flex: 1 1 100%;
  margin-top: var(--space-sm);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--border);
}

.template-create {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
}

.template-name-input,
.template-effort-input,
.template-owner-input {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.template-create-button {
  padding: 0.6rem 1rem;
  font-size: var(--font-body);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.template-create-button:disabled {
  opacity: 0.6;
  cursor: progress;
}

.template-create-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.template-list {
  list-style: none;
  margin: var(--space-sm) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.template-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.template-rename-input {
  flex: 1 1 12rem;
  min-width: 0;
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.template-edit-error {
  flex: 1 1 100%;
  margin: 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.template-delete {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  font-size: var(--font-body);
  color: var(--error-fg);
  font-weight: var(--weight-strong);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.template-delete:hover {
  border-color: var(--error-border);
}

.template-delete:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* Today/schedule surface (Issue #48/#163/T019): "My todo list" and "Member's todo list" are
   read-only claimed-chore views sharing the browse-by-room shape (T017) — no per-row delete, only
   a name/effort/schedule triplet — plus "My todo list"'s own two action buttons (mark done /
   remove from my list), styled as secondary buttons mirroring `.chore-claim`/`.chore-mark-done`
   (T016), not the accent-filled create/submit treatment. "Today's Schedule" is the one surface
   here with per-row actions (swap / not needed / mark done / undo), styled compactly like
   `.completed-today-undo` (T015) since a schedule row can carry up to three buttons at once.
   Error paragraphs keep the base error-text colour only, matching every prior surface's
   `*-error`/`*-row-error` precedent, never the full `.storage-warning`-style banner. */
.my-todo-list,
.member-todo-list {
  margin-top: 1rem;
}

.member-todo-select {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.my-todo-items,
.member-todo-items {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.my-todo-row,
.member-todo-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.my-todo-name,
.member-todo-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--font-body);
  color: var(--fg);
}

.my-todo-effort,
.my-todo-schedule,
.member-todo-effort,
.member-todo-schedule {
  flex: 0 0 auto;
  font-size: var(--font-small);
  color: var(--muted);
  white-space: nowrap;
}

.my-todo-last-completed-summary {
  flex: 1 1 100%;
  margin: 0;
  color: var(--muted);
  font-size: var(--font-small);
}

.my-todo-mark-done,
.my-todo-release {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.my-todo-mark-done:hover,
.my-todo-release:hover {
  background: var(--border);
}

.my-todo-mark-done:disabled,
.my-todo-release:disabled {
  opacity: 0.6;
  cursor: progress;
}

.my-todo-release-error {
  flex: 1 1 100%;
  margin: 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.daily-schedule {
  margin-top: 1rem;
}

.daily-schedule-member-select {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.daily-schedule-view,
.daily-schedule-refresh {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.daily-schedule-view:hover,
.daily-schedule-refresh:hover {
  background: var(--border);
}

.daily-schedule-view:disabled,
.daily-schedule-refresh:disabled {
  opacity: 0.6;
  cursor: progress;
}

.daily-schedule-error,
.daily-schedule-refresh-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.daily-schedule-body {
  margin-top: var(--space-sm);
}

.daily-schedule-capacity {
  margin: 0 0 var(--space-sm);
  color: var(--fg);
  font-size: var(--font-small);
}

.daily-schedule-items,
.daily-schedule-excluded-items {
  list-style: none;
  margin: var(--space-sm) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.daily-schedule-row,
.daily-schedule-excluded-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.daily-schedule-tier {
  flex: 0 0 auto;
  font-weight: var(--weight-strong);
  color: var(--fg);
  font-size: var(--font-small);
}

.daily-schedule-name,
.daily-schedule-excluded-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--font-body);
  color: var(--fg);
}

.daily-schedule-effort {
  flex: 0 0 auto;
  font-size: var(--font-small);
  color: var(--muted);
  white-space: nowrap;
}

.daily-schedule-swap,
.daily-schedule-not-needed,
.daily-schedule-mark-done,
.daily-schedule-undo {
  flex: 0 0 auto;
  padding: var(--space-3xs) var(--space-sm);
  font-size: var(--font-small);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.daily-schedule-swap:hover,
.daily-schedule-not-needed:hover,
.daily-schedule-mark-done:hover,
.daily-schedule-undo:hover {
  background: var(--border);
}

.daily-schedule-swap:disabled,
.daily-schedule-not-needed:disabled,
.daily-schedule-mark-done:disabled,
.daily-schedule-undo:disabled {
  opacity: 0.6;
  cursor: progress;
}

.daily-schedule-row-error {
  flex: 1 1 100%;
  margin: 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

/* HomePanel surface (Issue #48/#154/T020): the members/invitations management view mirrors
   `.rooms`/`.events`'s top-level section shape (T017/T018) — `.item-list`/`.item-row` (already
   styled) already carry the member/invitation rows. `.home-panel-error` gets only the base
   error-text colour, matching every other surface's `*-error` precedent — the full
   `.storage-warning`-style banner pattern is explicitly deferred to Issue #154, per this feature's
   own Assumptions. `.owner-badge` is a small accent-filled pill, mirroring
   `.view-toggle-button.active`'s emphasis treatment. The eight `*-pending-status`/`*-queued-status`
   classes (invite/leave/remove/revoke) split by what they represent: `*-pending-status` ("Checking
   connection…") is a brief in-flight check, muted like any other transient status text;
   `*-queued-status` ("Queued — will retry automatically") is genuinely the same "queued for retry
   once back online" state `.sync-indicator.pending`/`.offline-pending` already colour with
   `--sync-pending`, so it reuses that token rather than `--muted`. */
.home-panel {
  margin-top: 1rem;
}

.home-panel-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.owner-badge {
  display: inline-block;
  margin-left: var(--space-2xs);
  padding: var(--space-3xs) var(--space-xs);
  font-size: var(--font-small);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border-radius: var(--radius-sm);
}

.leave-home {
  margin-top: 1rem;
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.leave-home:hover {
  background: var(--border);
}

.leave-home:disabled {
  opacity: 0.6;
  cursor: progress;
}

.invite-pending-status,
.leave-pending-status,
.remove-pending-status,
.revoke-pending-status {
  color: var(--muted);
  font-size: var(--font-small);
}

.invite-queued-status,
.leave-queued-status,
.remove-queued-status,
.revoke-queued-status {
  color: var(--sync-pending);
  font-size: var(--font-small);
}

.invite-queued-status {
  margin: var(--space-2xs) 0 0;
}

/* Capacity surface (Issue #48/#154/T020): the override/default forms share the chore-create/
   event-create shape (T016/T018) — same input/button treatment, no new pattern invented.
   `*-set` buttons are the accent-filled primary submit (mirrors `.chore-create-button`);
   `.capacity-override-clear` is a secondary, non-destructive action (mirrors `.sign-out`/
   `.event-trigger`). `.capacity-default-display`/`.capacity-effective` get the same plain `--fg`
   treatment as `.capacity-completed-today` (T015) — sibling info paragraphs in the same section,
   not muted meta text. Error paragraphs keep the base error-text colour only, matching every prior
   surface's `*-error` precedent. Excludes `.capacity-completed-today`, already styled by T015. */
.capacity {
  margin-top: 1rem;
}

.capacity-override-form,
.capacity-default-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
  margin-top: 1rem;
}

.capacity-override-input,
.capacity-default-input {
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-body);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--elev-panel);
}

.capacity-override-set,
.capacity-default-set {
  padding: 0.6rem 1rem;
  font-size: var(--font-body);
  font-weight: var(--weight-strong);
  color: var(--on-accent);
  background: var(--accent);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.capacity-override-set:disabled,
.capacity-default-set:disabled {
  opacity: 0.6;
  cursor: progress;
}

.capacity-override-clear {
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-body);
  font-weight: var(--weight-normal);
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.capacity-override-clear:hover {
  background: var(--border);
}

.capacity-override-clear:disabled {
  opacity: 0.6;
  cursor: progress;
}

.capacity-override-error,
.capacity-default-error {
  margin: var(--space-2xs) 0 0;
  color: var(--error-fg);
  font-size: var(--font-small);
}

.capacity-default-display,
.capacity-effective {
  margin: var(--space-2xs) 0 0;
  color: var(--fg);
}

/* Test-only harness markup (T022) — `.repair-harness`/`.stand-in-reconcile` mount only inside
   `#[cfg(test)]` doc.rs/app.rs test bodies, never in production views. No real user-facing styling
   requirement (data-model.md) — just enough that neither renders visibly broken. */
.repair-harness {
  display: block;
  margin: var(--space-2xs) 0;
}

.stand-in-reconcile {
  display: block;
  margin: 0;
}
