/* Kinward's display voice — Fraunces, the same soft modern serif the app uses for
   headings (self-hosted variable font, no runtime download). Body/buttons stay
   sans, mirroring the app: serif headers, sans options. */
@font-face {
  font-family: 'Fraunces';
  src: url('/fonts/fraunces.ttf') format('truetype-variations');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Warm, caring palette — friendly pine green on cream/sand neutrals, with a
     soft terracotta accent. Deliberately warmer than the old cool blue-grey. */
  --serif: 'Fraunces', Georgia, 'Times New Roman', serif;
  --bg: #faf6f0;
  --panel: #fffdfa;
  --panel-raised: #fffdfa;
  --border: #e6ddcf;
  --text: #2a2620;
  --muted: #7a7065;
  --accent: #1f7a5c;
  --on-accent: #ffffff;      /* text/icons on an --accent fill */
  --accent-soft: #e2f0e8;
  --accent-2: #bf6a40;       /* terracotta, for gentle warm highlights */
  --accent-2-soft: #fbe6d8;
  --danger: #b23b3b;
  --danger-soft: #f8e3df;
  --warn: #b7771f;
  --warn-soft: #f8edd8;
  --ok: #2f8f5b;
  --ok-soft: #e2f1e8;
  --shadow: 0 1px 2px rgba(58, 46, 30, 0.04), 0 4px 16px rgba(58, 46, 30, 0.06);

  /* One spacing scale, so padding and gaps stop being chosen per component. Cards are
     separated by more than their own internal padding — without that a page of cards
     reads as one striped slab rather than as distinct things. */
  --s-1: 6px;  --s-2: 10px; --s-3: 14px; --s-4: 20px; --s-5: 28px; --s-6: 40px;
  --radius: 14px;
  --radius-sm: 9px;
}

/* Dark theme — follows the system setting, like the app (Android uses
   isSystemInDarkTheme). Mirrors the app's dark palette: warm near-black grounds,
   cream text, a lighter mint primary (so --on-accent flips to dark), soft
   terracotta. Everything is token-driven, so components need no dark-specific CSS. */
/* Dark theme, reachable two ways.

   It followed the system setting only, which is right until somebody wants to disagree
   with their system — a person on a bright laptop reading at night, or the reverse. The
   footer toggle stamps data-theme on <html>; "System" removes it and the media query is
   back in charge.

   `:not([data-theme="light"])` is what lets an explicit LIGHT choice win on a machine set
   to dark. Without it the media query would still fire and the toggle would work in one
   direction only. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #1a1712;
    --panel: #221e17;
    --panel-raised: #2b261d;
    --border: #453e32;
    --text: #ede4d7;
    --muted: #b0a693;
    --accent: #74d3ac;
    --on-accent: #04281c;
    --accent-soft: #1c4535;
    --accent-2: #f0b493;
    --accent-2-soft: #4a2f1e;
    --danger: #e8837b;
    --danger-soft: #3d211f;
    --warn: #e0a95a;
    --warn-soft: #382d19;
    --ok: #6fce9c;
    --ok-soft: #17362a;
    --shadow: none;
    color-scheme: dark;
  }
}
/* The same palette for an explicit choice. Generated from one source alongside the block
   above — if you edit one by hand, edit both. */
:root[data-theme="dark"] {
    --bg: #1a1712;
    --panel: #221e17;
    --panel-raised: #2b261d;
    --border: #453e32;
    --text: #ede4d7;
    --muted: #b0a693;
    --accent: #74d3ac;
    --on-accent: #04281c;
    --accent-soft: #1c4535;
    --accent-2: #f0b493;
    --accent-2-soft: #4a2f1e;
    --danger: #e8837b;
    --danger-soft: #3d211f;
    --warn: #e0a95a;
    --warn-soft: #382d19;
    --ok: #6fce9c;
    --ok-soft: #17362a;
    --shadow: none;
    color-scheme: dark;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; color: var(--text); background: var(--bg); }
/* 15px, not 13. The people reading this are caregivers in their fifties and sixties, and
   the app they use on their phone is deliberately large-print. */
body { font-size: 15px; line-height: 1.55; }
/* One column with a fixed header, at every width. The 260px sidebar is now a drawer, so
   the content gets the whole page and the layout stops being two different layouts. */
body { display: flex; flex-direction: column; min-height: 100vh; padding-top: var(--top-h); }
main { flex: 1 0 auto; width: 100%; }

/* Serif headings (Fraunces) — the app's editorial voice; softer "SOFT" axis and
   display optical size so titles read friendly rather than spiky. */
h1, h2, h3, .card h3, .tone-modal-header {
  font-family: var(--serif);
  font-weight: 600;
  letter-spacing: -0.01em;
  font-variation-settings: "SOFT" 58, "opsz" 30, "WONK" 0;
}
main h2 { font-size: 31px; line-height: 1.15; letter-spacing: -0.02em; margin-bottom: var(--s-2); }

/* The drawer. Off-canvas and translated rather than display:none'd, so it slides and so
   its contents keep their layout while hidden. `visibility` joins the transition to take
   it out of the tab order when shut — a transform alone leaves every link focusable
   off-screen, which walks a keyboard user through an invisible menu. */
.sidebar {
  /* Starts BELOW the header rather than covering it, so the bar — and the hamburger that
     opened this — stays put and stays usable while the menu is open. */
  position: fixed; top: calc(var(--top-h) + env(safe-area-inset-top));
  left: 0; bottom: 0; z-index: 70;
  width: 284px; max-width: 86vw;
  background: var(--panel); border-right: 1px solid var(--border);
  padding: var(--s-4) var(--s-3);
  display: flex; flex-direction: column; gap: var(--s-4);
  overflow-y: auto; overscroll-behavior: contain;
  transform: translateX(-100%); visibility: hidden;
  transition: transform .22s ease, visibility .22s;
}
body.drawer-open .sidebar { transform: translateX(0); visibility: visible; }
@media (prefers-reduced-motion: reduce) { .sidebar { transition: none; } }

/* Dims the page and swallows the click that closes the drawer. Stops at the header for the
   same reason the drawer does: dimming the bar would make the button you just pressed look
   disabled, and the way back out is that button. */
.scrim:not([hidden]) {
  position: fixed; inset: calc(var(--top-h) + env(safe-area-inset-top)) 0 0 0; z-index: 60;
  background: rgba(20, 16, 10, 0.42);
  opacity: 0; transition: opacity .22s ease;
}
body.drawer-open .scrim { opacity: 1; }

/* Fixed, so they stay put while the page scrolls; body reserves --top-h above and --tab-h
   below. --tab-h was referenced in four places as `var(--tab-h, 60px)` and never defined
   anywhere, so every one of them used the fallback while the bar actually measures 66 —
   which is why the footer's legal line sat underneath it on a phone. */
:root { --top-h: 56px; --tab-h: 66px; }
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 55;
  height: calc(var(--top-h) + env(safe-area-inset-top));
  padding: env(safe-area-inset-top) var(--s-3) 0;
  display: flex; align-items: center; gap: var(--s-2);
  background: var(--panel); border-bottom: 1px solid var(--border);
}
.topbar-brand {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--serif); font-size: 21px; font-weight: 600;
  color: var(--accent); text-decoration: none; letter-spacing: -0.02em;
}
/* Height-driven, with width auto: the mark is 53x72, and fixing both would squash it the
   moment the source art is replaced with a differently-proportioned one. Slightly taller
   than the wordmark's cap height, which is how the lockup is drawn everywhere else.

   On its own cream ground, which is not decoration. The mark is two-tone — dark green and
   terracotta — drawn for a light background: measured straight on the dark header it comes
   out at 2.2:1 and is a smudge. Recolouring it would flatten one of its two colours, so it
   keeps its art and gets the ground the brand icon already uses (the #F7F1E8 plate in
   Kinward.Icon.svg). Same treatment in both themes, so it reads as the app icon people
   already tap on their phone rather than as two different marks. */
.topbar-mark {
  height: 32px; width: auto; display: block;
  box-sizing: border-box; padding: 3px 4px;
  background: #f7f1e8; border-radius: 8px;
}
.topbar #mobile-menu-btn { margin-left: auto; }

/* Square, quiet, and big enough to hit — 40px, above the 24px these were as text buttons. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0; flex: none;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; color: var(--text); cursor: pointer;
}
.icon-btn:hover { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.icon-btn:not([hidden]) { display: inline-flex; }
/* Legal + the theme toggle, under the content rather than in the menu. Its own footer
   because <main> is replaced wholesale on every navigation. */
.page-footer {
  /* No top margin. <main> already grows to fill the column, so a margin here is added to a
     box that is exactly viewport-height and puts a scrollbar on every short page. The gap
     above the rule comes from main's own bottom padding. */
  flex: none;
  border-top: 1px solid var(--border); background: var(--panel);
  padding: var(--s-4) var(--s-6);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap;
}
.footer-legal { font-size: 12px; line-height: 1.5; color: var(--muted); }
.footer-legal a { color: var(--muted); }
.footer-legal div { margin-top: 4px; }

/* Three states, not two: a plain light/dark switch cannot say "whatever my machine says",
   and that is what most people want most of the time. */
.theme-toggle { display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--border);
  border-radius: 999px; background: var(--bg); }
.theme-toggle button {
  border: none; background: none; color: var(--muted);
  padding: 6px 14px; border-radius: 999px; font-size: 13px; font-weight: 600;
  min-height: 0; cursor: pointer;
}
.theme-toggle button:hover { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.theme-toggle button[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }

.badge { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 11px;
  font-weight: 600; background: var(--accent-soft); color: var(--accent); }
.badge.danger { background: var(--danger-soft); color: var(--danger); }
/* A heading over a run of cards — "Your loved ones", "Shared with you". */
main h3.group-title { margin: var(--s-4) 0 var(--s-2); font-size: 15px; color: var(--muted); font-weight: 600;
  text-transform: uppercase; letter-spacing: .04em; }
main h3.group-title:first-of-type { margin-top: 0; }
.badge.warn { background: var(--warn-soft); color: var(--warn); }
.badge.ok { background: var(--ok-soft); color: var(--ok); }
.avatar { width: 24px; height: 24px; border-radius: 50%; vertical-align: middle; margin-right: 6px; object-fit: cover; }


nav { display: flex; flex-direction: column; gap: 1px; }
/* Every row is icon-then-label now, as on the app drawer, so it is a flex row rather than
   a block. The icon is dimmer than the label at rest — it is a landmark for finding the
   row again, not a thing to read — and takes the row's colour when active. */
nav a { display: flex; align-items: center; gap: 11px;
  padding: 8px 11px; border-radius: var(--radius-sm); color: var(--text);
  text-decoration: none; font-size: 14.5px; border-left: 3px solid transparent; }
.nav-icon { width: 20px; height: 20px; flex: none; color: var(--muted); }
nav a:hover .nav-icon, nav a.active .nav-icon, .nav-person:hover .nav-icon { color: inherit; }
nav a.active .nav-icon { color: var(--accent); }
nav a:hover { background: var(--accent-soft); }
/* Was a solid accent pill — the loudest element on every screen, for a label. Soft fill
   plus a rule reads as "you are here" without competing with the page's own actions. */
nav a.active { background: var(--accent-soft); color: var(--accent); font-weight: 600;
  border-left-color: var(--accent); }

main { padding: var(--s-5) var(--s-6); max-width: 1040px; margin: 0 auto; }
main h2 { margin-top: 0; }
main p.lede { color: var(--muted); margin-top: 0; margin-bottom: var(--s-4); font-size: 16px; max-width: 68ch; }
/* "Dad › Medications": the person, quieter, so the section still reads as the title. */
main h2.scoped .crumb-person { color: var(--muted); font-weight: 500; }

.card { background: var(--panel-raised); border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--s-4) var(--s-4); margin-bottom: var(--s-3); box-shadow: var(--shadow); }
/* Long prose inside a card still needs a measure; full-bleed 1100px lines are unreadable. */
.card p { max-width: 74ch; }
.card h3 { margin: 0 0 var(--s-2); font-size: 18px; }
/* The sentence under a card heading explains the card; it should not compete with it. */
.card h3 + p.muted, .card h3 + .hint { margin-top: calc(var(--s-2) * -1); margin-bottom: var(--s-3); }
a.card { transition: box-shadow .14s ease, transform .14s ease; }
a.card:hover { box-shadow: 0 2px 6px rgba(58,46,30,0.06), 0 8px 24px rgba(58,46,30,0.09); transform: translateY(-1px); }
.card .meta { color: var(--muted); font-size: 12px; }

.grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* Benefits questionnaire: numbered steps, label-over-input fields in a two-up grid, help
   beneath. It was one flex row per question with the label, input, help and a status all
   fighting for the same line. */
.q-summary { cursor: pointer; font-weight: 600; font-size: 17px; }
.q-intro { margin: var(--s-2) 0 0; max-width: 62ch; }
.q-section { margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--border); }
.q-title { display: flex; align-items: center; gap: 10px; margin: 0 0 var(--s-3); font-size: 15px; font-weight: 600; }
.q-step { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent); font-size: 12px; font-weight: 700; flex: none; }
.q-grid { display: grid; gap: var(--s-3) var(--s-4); grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
.q-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.q-field input, .q-field select { width: 100%; max-width: 100%; box-sizing: border-box; }
.q-field input[type=number], .q-field input[type=date] { max-width: 220px; }
.q-field select { max-width: 320px; }
.q-label { font-size: 14px; font-weight: 500; line-height: 1.35; }
.q-req { display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px; font-size: 11px; font-weight: 600;
  background: var(--accent-soft); color: var(--accent); vertical-align: 1px; }
.q-help { font-size: 12.5px; color: var(--muted); line-height: 1.4; max-width: 44ch; }
.qstatus { margin-left: 8px; font-size: 12px; font-weight: 400; color: var(--muted); }
.q-actions { margin-top: var(--s-4); padding-top: var(--s-3); border-top: 1px solid var(--border); }

/* Every button used to be a filled accent pill, so "Remove", "History" and "Create family"
   all carried the same weight and a page had six primary actions. Filled is now reserved
   for the one thing a screen is for; everything else is a quiet outline, and destructive
   actions read as danger only on hover — visible when wanted, not alarming at rest. */
button, .btn { background: var(--panel); color: var(--text); border: 1px solid var(--border);
  padding: 9px 15px; border-radius: var(--radius-sm); font-size: 14px; font-weight: 600;
  cursor: pointer; transition: background .12s ease, border-color .12s ease, color .12s ease; }
/* .btn is worn by anchors as well as buttons — Home's empty states use one — and an anchor
   keeps its underline through the rule above. Scoped to a.btn rather than added to every
   button, so nothing else changes its display. */
a.btn { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
button:hover, .btn:hover { background: var(--accent-soft); border-color: var(--accent); }
button.primary, .btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
button.primary:hover, .btn.primary:hover { filter: brightness(1.06); background: var(--accent); }
button.secondary { background: var(--panel); color: var(--text); border: 1px solid var(--border); font-weight: 500; }
button.danger { background: var(--panel); color: var(--danger); border-color: var(--border); }
button.danger:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
button:disabled { opacity: 0.45; cursor: not-allowed; }
button:disabled:hover { background: var(--panel); border-color: var(--border); }
button:focus-visible, .btn:focus-visible, nav a:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; }
button.small, .btn.small { font-size: 12.5px; padding: 5px 10px; }

/* An action carrying its meaning in a glyph rather than a word.
   Square, so a row of them reads as a row rather than as buttons of assorted widths, and
   44px at the tap target — a caregiver doing this on a phone is the common case. There is
   no visible label, so every one of these MUST carry an aria-label and a title: the first
   is what a screen reader announces, the second is what everybody else gets on hover. */
.icon-btn { display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0; border-radius: var(--radius-sm); }
.icon-btn svg { width: 19px; height: 19px; }
.icon-btn.danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.icon-row { display: inline-flex; gap: 6px; align-items: center; }
@media (max-width: 640px) {
  .icon-btn { width: 44px; height: 44px; }
}

input, select, textarea { font-family: inherit; font-size: 14px; padding: 9px 12px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--bg); color: var(--text); }
/* A field on the same row as a button that is 4px taller looks like a mistake. */
input::placeholder, textarea::placeholder { color: var(--muted); opacity: .85; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
textarea { width: 100%; min-height: 90px; resize: vertical; }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.row > * { flex: 0 0 auto; }
.row .grow { flex: 1 1 auto; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 11px 12px; border-bottom: 1px solid var(--border); font-size: 14px; vertical-align: top; }
tbody tr:last-child td { border-bottom: none; }
th { color: var(--muted); font-weight: 500; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }

.flag { color: var(--danger); font-weight: 600; }
.muted { color: var(--muted); }
.tag { display: inline-block; background: var(--accent-soft); color: var(--accent); padding: 2px 8px; border-radius: 999px; font-size: 11px; margin-right: 4px; }
/* An empty list is a normal state, not a fault. Centred and given room, it reads as
   "nothing here yet" rather than as a failed render. */
.empty { color: var(--muted); font-style: normal; text-align: center; padding: var(--s-4) var(--s-3); }
.ai-output { background: var(--accent-soft); border-left: 3px solid var(--accent); padding: 10px 12px; border-radius: 6px; margin-top: 8px; font-size: 13px; }
.toast { position: fixed; bottom: 20px; right: 20px; background: var(--text); color: var(--bg); padding: 10px 16px; border-radius: 6px; font-size: 13px; opacity: 0; transition: opacity 0.2s; pointer-events: none; }
.toast.show { opacity: 1; }

.invite-banner { background: var(--warn-soft); border-bottom: 2px solid var(--warn); color: var(--text); padding: 12px 18px; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 14px; }
.invite-banner code { background: rgba(0,0,0,0.08); padding: 1px 6px; border-radius: 4px; font-size: 13px; }
.invite-banner-actions { display: flex; gap: 8px; }
.invite-banner button { padding: 6px 12px; font-size: 13px; }
.invite-banner button.secondary { background: transparent; border: 1px solid var(--border); color: var(--text); }

/* ── Chat / mediation view ────────────────────────────────────────────── */
.chat-layout { display: grid; grid-template-columns: 240px 1fr; gap: 14px; align-items: start; }
.chat-sidebar { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 12px; position: sticky; top: 16px; }
.chat-list { list-style: none; padding: 0; margin: 0; }
.chat-list li { padding: 8px 10px; border-radius: 6px; cursor: pointer; margin-bottom: 2px; }
.chat-list li:hover { background: var(--accent-soft); }
.chat-list li.active { background: var(--accent); color: var(--on-accent); }
.chat-list li.active .chat-list-meta { color: var(--on-accent); }
.chat-list-topic { font-size: 13px; font-weight: 500; }
.chat-list-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }
.chat-list li.empty { color: var(--muted); font-style: italic; cursor: default; }
.chat-list li.empty:hover { background: transparent; }

.chat-pane { padding: 0; display: flex; flex-direction: column; min-height: 520px; }
.chat-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.chat-scroll { flex: 1; overflow-y: auto; padding: 16px 18px; max-height: 60vh; }
.chat-composer { border-top: 1px solid var(--border); padding: 12px 18px; }

.bubble-row { display: flex; margin-bottom: 12px; }
.bubble-row.mine { justify-content: flex-end; }
.bubble-row.theirs { justify-content: flex-start; }
.bubble { max-width: 70%; padding: 10px 12px; border-radius: 14px; background: var(--panel); border: 1px solid var(--border); }
.bubble-row.mine .bubble { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.bubble-row.mine .bubble .bubble-speaker { color: var(--on-accent); }
.bubble-row.mine .bubble .link { color: var(--on-accent); }
.bubble-speaker { font-size: 11px; color: var(--muted); margin-bottom: 2px; font-weight: 500; }
.bubble-text { font-size: 14px; line-height: 1.4; white-space: pre-wrap; word-wrap: break-word; }
.bubble-actions { margin-top: 4px; }
.bubble-clarify { margin-top: 6px; }
.bubble-row.mine .bubble-clarify .ai-output { background: rgba(255,255,255,0.15); color: var(--on-accent); border-left-color: rgba(255,255,255,0.5); }

.summary-block { position: relative; padding-right: 32px; }
.summary-close { position: absolute; top: 4px; right: 6px; background: none; border: none; color: var(--muted); font-size: 18px; line-height: 1; padding: 2px 6px; cursor: pointer; border-radius: 4px; }
.summary-close:hover { background: var(--border); color: var(--text); }

.clarify-block { position: relative; padding-right: 32px; }
.clarify-close { position: absolute; top: 4px; right: 6px; background: none; border: none; color: var(--muted); font-size: 18px; line-height: 1; padding: 2px 6px; cursor: pointer; border-radius: 4px; }
.clarify-close:hover { background: var(--border); color: var(--text); }
.suggested-reply { margin-top: 10px; padding: 10px 12px; background: var(--panel); border: 1px dashed var(--accent); border-radius: 8px; }
.bubble-row.mine .suggested-reply { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.6); color: var(--on-accent); }
.suggested-reply-text { font-size: 14px; line-height: 1.4; font-style: italic; }

.link { background: none; border: none; color: var(--accent); padding: 0; font-size: 12px; cursor: pointer; text-decoration: underline; }
.link:hover { opacity: 0.8; }

.who-toggle { background: var(--panel); color: var(--text); border: 1px solid var(--border); padding: 4px 12px; font-size: 12px; border-radius: 999px; cursor: pointer; }
.who-toggle.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }

.tone-modal-overlay { position: fixed; inset: 0; background: rgba(20, 20, 30, 0.55); display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 20px; }
.tone-modal { background: var(--panel); border-radius: 12px; max-width: 480px; width: 100%; padding: 22px 24px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); }
.tone-modal-header { font-size: 17px; font-weight: 600; margin-bottom: 8px; }
.tone-modal-reason { font-size: 14px; color: var(--text); margin-bottom: 14px; line-height: 1.4; }
.tone-modal-original, .tone-modal-softer { margin-bottom: 12px; }
.tone-modal-quote { padding: 8px 12px; border-left: 3px solid var(--border); background: var(--bg); border-radius: 4px; font-size: 13px; line-height: 1.4; white-space: pre-wrap; }
.tone-modal-quote.softer { border-left-color: var(--accent); background: var(--accent-soft); }
.tone-modal-topic { margin-bottom: 12px; padding: 10px 12px; background: #fff4e0; border-left: 3px solid #e8c994; border-radius: 4px; }
.tone-modal-topic-body { font-size: 13px; line-height: 1.45; color: #5a3a08; }
.tone-modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px; flex-wrap: wrap; }

.mediate-modal { max-width: 580px; }
.mediate-section { margin-bottom: 14px; }
.mediate-section-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 4px; }
.mediate-section-body { font-size: 14px; line-height: 1.5; }
.mediate-next .mediate-section-body { background: var(--accent-soft); border-left: 3px solid var(--accent); padding: 10px 12px; border-radius: 4px; }
.mediate-sides { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.mediate-side { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; }
.mediate-side-name { font-weight: 600; font-size: 13px; margin-bottom: 6px; }
.mediate-side-row { font-size: 12px; line-height: 1.4; margin-bottom: 4px; }
.mediate-side-label { font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); display: block; }
@media (max-width: 600px) { .mediate-sides { grid-template-columns: 1fr; } }

/* ── Responsive: tablet & mobile ───────────────────────────────────────── */
@media (max-width: 900px) {
  /* The body is no longer a grid — the sidebar it narrowed is a drawer now. */
  main { padding: 20px 22px; }
  .chat-layout { grid-template-columns: 200px 1fr; }
  .chat-scroll { max-height: 55vh; }
}

/* ── Mobile shell: bottom tab bar + slim top bar + two-screen chat ──────── */
.mobile-tabs { display: none; }
.mobile-menu-btn { display: none; }
.chat-back { display: none; }
.chat-overflow { display: none; }

@media (max-width: 720px) {
  /* The shell is the same shape at every width now — header, drawer, footer — so the
     phone only has to add room for the bottom tab bar. The rules that turned .sidebar
     into a slim top bar are gone: it is the drawer, and the header is a real element.
     `.sidebar nav { display: none }` went with them, which is what used to leave the
     phone with no menu of its own and made the More sheet a second implementation. */
  body { padding-bottom: calc(var(--tab-h, 60px) + env(safe-area-inset-bottom)); }

  /* The footer clears the fixed tab bar itself. body's padding-bottom cannot do it: body is
     height:100%, and content that overflows a fixed-height box does not honour its bottom
     padding — so the last thing on the page kept ending up underneath the tabs. */
  .page-footer {
    padding: var(--s-4);
    padding-bottom: calc(var(--s-4) + var(--tab-h) + env(safe-area-inset-bottom));
    flex-direction: column; align-items: flex-start;
  }
  .mobile-menu-btn:active { background: var(--accent-soft); color: var(--accent); }

  /* Bottom tab bar */
  .mobile-tabs {
    display: flex;
    flex-direction: row;
    position: fixed;
    bottom: 0; left: 0; right: 0;
    z-index: 50;
    background: var(--panel);
    border-top: 1px solid var(--border);
    padding: 6px 4px;
    padding-bottom: calc(6px + env(safe-area-inset-bottom));
    gap: 2px;
    justify-content: space-around;
    box-shadow: 0 -2px 10px rgba(0,0,0,0.04);
  }
  .mobile-tabs .tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 6px 4px;
    border: none;
    background: none;
    color: var(--muted);
    text-decoration: none;
    font-size: 11px;
    font-weight: 500;
    border-radius: 8px;
    min-height: 48px;
    cursor: pointer;
  }
  .mobile-tabs .tab svg { width: 22px; height: 22px; }
  .mobile-tabs .tab.active { color: var(--accent); }
  .mobile-tabs .tab:active { background: var(--accent-soft); }

  /* Main view */
  main { padding: 14px; max-width: none; }
  main h2 { font-size: 20px; margin-top: 0; }
  main p.lede { font-size: 14px; }

  /* Cards & grid */
  .card { padding: 14px; margin-bottom: 12px; }
  .grid { grid-template-columns: 1fr; gap: 12px; }

  /* iOS Safari zooms on inputs with font-size < 16px */
  input, select, textarea { font-size: 16px; padding: 9px 10px; }
  button, .btn { font-size: 14px; padding: 9px 14px; min-height: 38px; }
  button.small, .btn.small { font-size: 12px; padding: 6px 10px; min-height: 0; }

  /* Tables: horizontal scroll instead of squishing */
  table { display: block; overflow-x: auto; white-space: nowrap; }
  th, td { font-size: 12px; padding: 6px 8px; }

  /* ─── Chat: two-screen pattern (list ↔ active conversation) ─────────── */
  .chat-layout { grid-template-columns: 1fr; gap: 0; }
  /* Default state: no active chat — show the list full-width, hide the pane */
  .chat-sidebar {
    position: static;
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px;
    max-height: none;
  }
  .chat-pane { display: none; }

  /* Active state: hide the list, show the pane filling the viewport */
  body.chat-mobile-active main { padding: 0; }
  body.chat-mobile-active main h2,
  body.chat-mobile-active main p.lede { display: none; }
  body.chat-mobile-active .chat-sidebar { display: none; }
  body.chat-mobile-active .chat-pane {
    display: flex;
    flex-direction: column;
    border: none;
    border-radius: 0;
    background: var(--panel);
    height: calc(100dvh - var(--top-h, 52px) - var(--tab-h, 60px) - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  }

  .chat-header {
    padding: 8px 12px;
    flex-wrap: nowrap;
    gap: 6px;
    border-bottom: 1px solid var(--border);
  }
  .chat-back {
    display: inline-flex;
    align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border-radius: 8px;
    background: none;
    border: none;
    color: var(--accent);
    padding: 0;
    cursor: pointer;
    flex: 0 0 auto;
  }
  .chat-back:active { background: var(--accent-soft); }
  .chat-header-title { flex: 1 1 auto; min-width: 0; }
  .chat-header-title h3 { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .chat-header-title .muted { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Hide the wide action row, show a single ⋯ button that toggles it */
  .chat-header-actions { display: none; position: absolute; right: 8px; top: 48px; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 6px; flex-direction: column; gap: 4px; box-shadow: 0 8px 24px rgba(0,0,0,0.12); z-index: 20; min-width: 200px; }
  .chat-header-actions.show-overflow { display: flex; }
  .chat-header-actions button { width: 100%; text-align: left; justify-content: flex-start; }
  .chat-overflow {
    display: inline-flex;
    align-items: center; justify-content: center;
    width: 36px; height: 36px; padding: 0;
    font-size: 20px;
    background: none;
    border: 1px solid var(--border);
    color: var(--text);
    flex: 0 0 auto;
  }
  .chat-header { position: relative; }

  /* Conversation list back outside active state */
  .chat-list-delete { opacity: 0.5; }
  .chat-list li { padding-right: 28px; padding: 12px 28px 12px 12px; }
  .chat-list-topic { font-size: 14px; }
  .chat-list-meta { font-size: 12px; }

  /* Scroll + composer: composer pinned to bottom of pane */
  .chat-scroll { flex: 1 1 auto; padding: 12px; max-height: none; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .chat-composer { border-top: 1px solid var(--border); padding: 10px 12px; background: var(--panel); }
  .chat-composer .row { flex-wrap: nowrap; }
  .chat-composer .msg { flex: 1 1 auto; min-width: 0; }
  .bubble { max-width: 85%; }
  .bubble-text { font-size: 15px; }
  .topics-bar { padding: 8px 12px; }

  /* Modals: fit screen, action buttons stack full-width */
  .tone-modal-overlay { padding: 12px; align-items: flex-start; padding-top: 32px; }
  .tone-modal { padding: 18px 18px 16px; max-width: 100%; max-height: calc(100vh - 64px); overflow-y: auto; }
  .tone-modal-header { font-size: 16px; }
  .tone-modal-actions { flex-direction: column-reverse; align-items: stretch; gap: 6px; }
  .tone-modal-actions button { width: 100%; }
  .mediate-modal { max-width: 100%; }

  /* Popovers: don't overflow viewport */
  .tone-popover, .demo-popover { width: 260px; max-width: calc(100vw - 32px); right: 0; }

  /* Invite banner stacks */
  .invite-banner { flex-direction: column; align-items: stretch; gap: 8px; }
  .invite-banner-actions { justify-content: flex-end; }

  /* Toast moves up so composer doesn't cover it */
  .toast { bottom: calc(70px + env(safe-area-inset-bottom)); left: 12px; right: 12px; text-align: center; }
}

@media (max-width: 420px) {
  main { padding: 12px; }
  .bubble { max-width: 90%; }
  .chat-header-title h3 { font-size: 14px; }
  .topic-chip { font-size: 11px; }
}

/* Touch devices: no hover-to-reveal */
@media (hover: none) {
  .chat-list-delete { opacity: 0.6; }
}

/* ── Bottom sheet (More menu, account menu) ────────────────────────────── */
.sheet-overlay {
  position: fixed; inset: 0;
  background: rgba(20, 20, 30, 0.45);
  z-index: 200;
  display: flex; align-items: flex-end; justify-content: center;
  animation: sheet-fade 0.15s ease;
}
.sheet {
  width: 100%;
  max-width: 480px;
  background: var(--panel);
  border-radius: 16px 16px 0 0;
  padding: 12px 16px calc(20px + env(safe-area-inset-bottom));
  box-shadow: 0 -8px 30px rgba(0,0,0,0.18);
  animation: sheet-slide 0.18s ease;
  display: flex; flex-direction: column; gap: 4px;
}
.sheet-handle {
  width: 40px; height: 4px;
  background: var(--border);
  border-radius: 999px;
  margin: 0 auto 8px;
}
.sheet-title { font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; padding: 0 4px; }
.sheet-list { display: flex; flex-direction: column; gap: 2px; }
.sheet-item {
  display: block;
  padding: 14px 12px;
  font-size: 15px;
  color: var(--text);
  text-decoration: none;
  border-radius: 8px;
}
.sheet-item:active { background: var(--accent-soft); }
.sheet-cancel {
  margin-top: 10px;
  padding: 12px;
  font-size: 15px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
}
.sheet-cancel.danger { color: var(--danger); border-color: var(--danger-soft); }
.sheet-account { padding: 4px 4px 12px; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
.sheet-account-name { font-size: 15px; font-weight: 600; }
.sheet-account-role { font-size: 12px; color: var(--muted); text-transform: capitalize; }
.sheet-field-label { display: block; font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin: 6px 4px 4px; }
.sheet-family { padding: 10px; font-size: 15px; border-radius: 8px; border: 1px solid var(--border); width: 100%; }
/* ── Centred dialog ────────────────────────────────────────────────────────
   The same sheet, brought to the middle of the screen. A short form that has to be
   answered or dismissed is modal in a way a menu is not, and on a desktop-width page a
   panel pinned to the bottom edge reads as something that arrived rather than something
   that was asked for.

   Below 640px it stays a bottom sheet: that is where a thumb is, and a dialog floating in
   the middle of a phone screen is the desktop idiom borrowed by something that should not
   have. One component, two placements — as with `anchored`. */
.sheet-overlay.centered { align-items: center; }
.sheet-overlay.centered .sheet {
  border-radius: 14px;
  max-width: 420px;
  padding: 18px;
  gap: 8px;
  animation: sheet-pop 0.14s ease;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.35);
}
.sheet-overlay.centered .sheet-handle { display: none; }
.sheet-dialog-title { font-size: 16px; font-weight: 600; margin: 0; }
.sheet-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }
@keyframes sheet-pop { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: none; } }
@media (max-width: 640px) {
  .sheet-overlay.centered { align-items: flex-end; }
  .sheet-overlay.centered .sheet {
    max-width: 480px;
    border-radius: 16px 16px 0 0;
    padding: 16px 16px calc(20px + env(safe-area-inset-bottom));
    animation: sheet-slide 0.18s ease;
  }
}
@media (prefers-reduced-motion: reduce) {
  .sheet-overlay.centered .sheet { animation: none; }
}

/* ── Anchored popover (the account menu) ───────────────────────────────────
   The account menu used to arrive as a bottom sheet, which is the idiom for something
   modal and thumb-reachable. This is neither: it is a short menu belonging to a button in
   the corner, and sliding it up from the far edge of the screen breaks the link between
   what was pressed and what appeared. It hangs off its button instead.

   The scrim goes transparent rather than away — it is still what catches the click that
   dismisses this, and a dark wash behind a small dropdown would read as modal. */
.sheet-overlay.anchored {
  background: transparent;
  display: block;
}
.sheet-overlay.anchored .sheet {
  position: fixed;
  width: max-content;
  min-width: 200px;
  /* Never wider than the screen it is pinned to, whatever is in it. */
  max-width: min(320px, calc(100vw - 16px));
  border-radius: 12px;
  border: 1px solid var(--border);
  padding: 6px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.16);
  /* Out of the corner it belongs to, rather than up from the bottom of the screen. */
  transform-origin: top right;
  animation: popover-in 0.13s ease;
  gap: 2px;
}
/* A bottom sheet needs a grab handle and an explicit Close; a popover has neither — it is
   dismissed by clicking away from it, which is what the transparent scrim above is for. */
.sheet-overlay.anchored .sheet-handle { display: none; }
.sheet-overlay.anchored .sheet-account { padding: 8px 10px 10px; margin-bottom: 6px; }
.sheet-overlay.anchored .sheet-item { padding: 10px; font-size: 14px; }
.sheet-overlay.anchored .sheet-item:hover { background: var(--accent-soft); }
.sheet-overlay.anchored .sheet-cancel { margin-top: 6px; padding: 10px; font-size: 14px; }
@keyframes popover-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
/* Whoever asked not to be animated at gets the menu, just not the movement. */
@media (prefers-reduced-motion: reduce) {
  .sheet-overlay.anchored .sheet { animation: none; }
}

@keyframes sheet-slide { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes sheet-fade { from { opacity: 0; } to { opacity: 1; } }

.disposition-control { display: flex; flex-direction: column; gap: 2px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); }
.disposition-control input[type=range] { width: 120px; accent-color: var(--accent); }
.chat-popover-wrap, .tone-popover-wrap, .demo-popover-wrap { position: relative; }
.chat-list li { position: relative; }
.chat-list-delete { position: absolute; top: 4px; right: 4px; background: none; border: none; color: var(--muted); font-size: 18px; line-height: 1; padding: 2px 6px; cursor: pointer; border-radius: 4px; opacity: 0; transition: opacity 0.15s; }
.chat-list li:hover .chat-list-delete { opacity: 1; }
.chat-list-delete:hover { background: rgba(220, 40, 40, 0.1); color: #c0392b; }
.chat-unread-badge { display: inline-block; background: var(--danger, #d33); color: white; font-size: 10px; font-weight: 700; padding: 1px 7px; border-radius: 999px; margin-left: 6px; vertical-align: middle; }
.chat-list li.active .chat-unread-badge { background: white; color: var(--accent); }

.topics-bar { padding: 8px 18px; border-bottom: 1px solid var(--border); background: var(--bg); }
.topic-chip { display: inline-flex; align-items: center; gap: 4px; background: #fff4e0; border: 1px solid #e8c994; color: #7a5410; font-size: 12px; padding: 2px 8px; border-radius: 999px; }
.topic-del { background: none; border: none; color: #a07635; cursor: pointer; font-size: 14px; line-height: 1; padding: 0 2px; }
.topic-del:hover { color: #c0392b; }
.bubble-topic-icon { margin-left: 4px; font-size: 12px; }
.sensitive-callout { background: #fff4e0; border: 1px solid #e8c994; color: #7a5410; padding: 1px 6px; border-radius: 4px; font-weight: 600; white-space: nowrap; }
.tone-popover, .demo-popover { position: absolute; top: calc(100% + 6px); right: 0; z-index: 50; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; box-shadow: 0 8px 24px rgba(0,0,0,0.12); width: 280px; box-sizing: border-box; }
.tone-popover .row { flex-wrap: nowrap; }
.tone-popover .muted { white-space: nowrap; flex-shrink: 0; }
.tone-popover input[type=range] { flex: 1 1 auto; min-width: 0; width: 100%; accent-color: var(--accent); margin: 0; }
.demo-popover input[type=range] { accent-color: var(--accent); }

/* Coverage banner — prepended inside <main> when the household's subscription has lapsed,
   is in its grace period, or covers fewer lines than it has loved ones. Absent entirely
   otherwise: a banner that is always there stops being read.

   Inside main, not beside it. The body is a two-column grid, so a sibling of <main> takes
   a grid cell of its own and pushes the whole content column onto the next row. */
.coverage-banner {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  margin: 0 0 14px; padding: 10px 14px; border-radius: 10px;
  background: #fdf3e7; border: 1px solid #e8c9a0; color: #7a4a12; font-size: 14px;
}
.coverage-banner a { color: inherit; font-weight: 600; }

/* Contact avatar — the photo if there is one, otherwise the initial. Fixed size so a list
   of contacts does not reflow as each photo arrives from its own authed fetch. */
.ct-avatar {
  width: 44px; height: 44px; flex: none; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft, #e8f0eb); color: var(--muted, #8A857E);
  font-weight: 600; font-size: 17px; overflow: hidden;
}
.ct-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ct-photo-label { cursor: pointer; text-decoration: underline; }

/* Household notices — what the loved one has asked OF the caregiver, above the dashboard
   tiles. Tinted with --warn rather than --danger: an unanswered request needs attention,
   but wanting a contact removed is not an emergency and should not be dressed as one. */
.notice-card { border-color: var(--warn); background: var(--warn-soft); }
.notice-card h3 { color: var(--warn); margin-bottom: var(--s-2); }

.notice-row {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-2) var(--s-2); margin: 0 calc(var(--s-2) * -1);
  border-radius: var(--radius-sm);
  color: inherit; text-decoration: none;
}
.notice-row:hover { background: rgba(0, 0, 0, 0.04); }
@media (prefers-color-scheme: dark) { .notice-row:hover { background: rgba(255, 255, 255, 0.06); } }

.notice-icon { font-size: 18px; line-height: 1.4; flex: none; }
.notice-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.notice-title { font-weight: 600; }
.notice-body { color: var(--muted); font-size: 14px; }
.notice-meta { color: var(--muted); font-size: 13px; }

/* Unread is MARKED, not coloured over: the row has to stay perfectly readable once it has
   been read, which is most of the time. Same rule the apps follow. */
.notice-dot {
  width: 9px; height: 9px; flex: none; margin-top: 7px;
  border-radius: 50%; background: var(--warn);
}
.notice-chevron { color: var(--muted); flex: none; font-size: 18px; line-height: 1.3; }

/* Person-first navigation — one section per loved one, matching the caregiver drawer on
   both apps. The person is a button rather than a link because it opens a section instead
   of going anywhere; it still has to look like it belongs in the same list. */
.nav-person {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 8px 11px; border: none; background: none; border-radius: var(--radius-sm);
  border-left: 3px solid transparent;
  font-size: 14.5px; font-weight: 600; color: var(--text);
  text-align: left; cursor: pointer;
}
.nav-person:hover { background: var(--accent-soft); border-color: transparent; }
.nav-person.open { color: var(--accent); }
/* Rotated rather than swapped between two characters: a glyph replaced mid-transition
   pops while the rows beneath it are still moving. */
.nav-person-caret {
  font-size: 11px; color: var(--muted); flex: none; margin-left: auto;
  transition: transform .22s ease, color .12s ease;
}
.nav-person.open .nav-person-caret { color: var(--accent); transform: rotate(90deg); }

/* A person's rows slide open instead of appearing.
   grid-template-rows 0fr -> 1fr is the one way to transition to a height nobody has
   measured: max-height needs a guess, and a guess that is too small clips the last row
   while one that is too large makes a short list crawl open at the wrong speed. The rows
   stay in the DOM either way, so `visibility` is what keeps a closed section's links out
   of the tab order — a keyboard user should not walk through a menu that is shut. */
.nav-sub-wrap {
  display: grid; grid-template-rows: 0fr;
  visibility: hidden;
  transition: grid-template-rows .22s ease, visibility .22s;
}
.nav-section.open .nav-sub-wrap { grid-template-rows: 1fr; visibility: visible; }
.nav-sub-inner { overflow: hidden; min-height: 0; }
@media (prefers-reduced-motion: reduce) {
  .nav-sub-wrap, .nav-person-caret { transition: none; }
}
.nav-person .nav-icon { color: var(--muted); }
.nav-person.open .nav-icon { color: var(--accent); }
.nav-person-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A person you are only a member of: the owner's name in small type under theirs, so the
   menu says which names are yours and which are shared with you. */
.nav-person-text { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.2; }
.nav-person-via { font-size: 11.5px; font-weight: 500; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-person.open .nav-person-via { color: var(--muted); }

/* Indented under the person they belong to. The rule down the left is what carries the
   grouping — indentation alone reads as an accident at this width. */
nav a.nav-sub {
  margin-left: 14px; padding-left: 12px; font-size: 14px; gap: 10px;
  border-left: 2px solid var(--border); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
nav a.nav-sub .nav-icon { width: 18px; height: 18px; }
nav a.nav-sub.active { border-left-color: var(--accent); }

.nav-rule { border: none; border-top: 1px solid var(--border); margin: var(--s-2) 0; }

/* The "More" sheet carries the same person sections as the sidebar — below 900px it IS
   the menu, so a person's name heads their rows here too. */
.sheet-group {
  padding: var(--s-3) var(--s-2) var(--s-1);
  font-size: 13px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  color: var(--muted);
}
.sheet-item.sheet-sub { padding-left: var(--s-4); }

/* Empty states — the app's own artwork, a sentence, and the one thing to do. Centred and
   given real height: on the apps these are the whole screen, and a 40px thumbnail with a
   line of grey text beside it is not the same reassurance as the shield filling the space
   where alerts would be. */
.empty-state {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--s-3); padding: var(--s-6) var(--s-4);
}
.empty-art { width: 100%; max-width: 320px; height: auto; }
.empty-body { max-width: 46ch; margin: 0; color: var(--muted); font-size: 16px; }

/* Alert rows: a large icon saying what KIND of thing this was, in the colour of how bad it
   was. Skimming a feed is the common case — you are looking for the one call that matters
   among a week of them — and a shape is faster to skim than a word. */
.alert-card { display: flex; align-items: flex-start; gap: var(--s-3); }
/* The one an email linked to. */
.alert-card.alert-linked { box-shadow: 0 0 0 3px var(--accent); }
.alert-main { flex: 1; min-width: 0; }
.alert-icon {
  flex: none; width: 46px; height: 46px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.alert-icon svg { width: 26px; height: 26px; }
/* On a phone the row is narrow enough that a 46px circle crowds the text beside it. */
@media (max-width: 720px) {
  .alert-icon { width: 38px; height: 38px; }
  .alert-icon svg { width: 22px; height: 22px; }
}

/* Row actions that are icons rather than words — archive, and its undo. Quiet at rest so a
   feed of forty rows is not forty buttons, and it takes its colour on hover. 34px, which is
   under the 44px touch target but sits inside a card that is itself the tap area on a
   phone; the button is the precise target for a pointer. */
.icon-action {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0; flex: none;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; color: var(--muted); cursor: pointer;
}
.icon-action svg { width: 19px; height: 19px; }
.icon-action:hover { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.icon-action:disabled { opacity: .45; cursor: not-allowed; }
.icon-action:disabled:hover { background: none; color: var(--muted); }
