/* duleva — app shell design system (Task 6).

   The single stylesheet every authenticated screen reuses. Tokens are the
   LOCKED chrome values (foundation-slice "Global Constraints"); they win over
   the visual-language doc where they differ (e.g. --radius:14px, not 12px).

   No CSS framework, mobile-first, server-rendered. Client JS is limited to the
   three sanctioned progressive enhancements (enhance.js) — this stylesheet is
   the source of truth for layout/colour/contrast so everything works with JS
   disabled. Member colours are NEVER hardcoded here: they are injected per chip
   as inline custom properties resolved from app.platform.profile.palette.COLORS.
*/

/* ---- Design tokens -------------------------------------------------------- */
:root {
  /* Chrome (locked). */
  --canvas: #FBF8F4;
  --surface: #FFFFFF;
  --ink: #1F1A1A;
  --muted: #6B6360;
  --hairline: #E7E2DD;
  --primary: #2E9C9C;
  --primary-tint: #E6F2F1;
  /* Feedback. */
  --alert: #C2452F;
  --alert-tint: #FBE4DC;
  /* Sage (the "bought" tick fill + the partner-ping banner) and the butter
     paper accent (the one-off left border). From the locked visual language. */
  --sage: #5B8C6E;
  --p-butter: #FCF3C9;

  --radius: 14px;
  --maxw: 480px;       /* max content width */
  --gutter: 16px;
  --nav-h: 92px;       /* floating nav + breathing room reserved under <main> */

  --shadow-raised: 0 1px 2px rgba(40, 30, 20, .05);
  --shadow-float: 0 12px 30px rgba(40, 30, 20, .14);
  /* Desaturated mid-tone used for placeholder/unfilled UI (dashed avatar ring,
     grip bar, sheet close button background). Sits between --hairline and --muted. */
  --placeholder: #CBC3B8;
}

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

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

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  min-height: 100dvh;
}

a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Honour the OS reduce-motion setting for every transition/animation. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ---- App layout ----------------------------------------------------------- */
.app {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  position: relative;
  min-height: 100dvh;
}

/* Header: account chip (left) · centered title · notes + bell (right). */
.topbar {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 14px var(--gutter) 10px;
  /* Safe-area inset for notched devices. */
  padding-top: max(14px, env(safe-area-inset-top));
}
.topbar .ttl {
  flex: 1;
  text-align: center;
  font-weight: 600;
  font-size: 16px;
  /* Keep a long title on one line; never push the side controls off-screen. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.acctbtn {
  flex: 0 0 auto;
  display: inline-flex;
  border-radius: 50%;
}

.iconbtn {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: var(--ink);
  position: relative;
}
.iconbtn svg { width: 19px; height: 19px; }
/* Count badge over a top-bar icon (notes / bell). Hidden at zero. */
.iconbtn .count {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 9px;
  background: var(--primary);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  border: 2px solid var(--canvas);
}
.iconbtn .count[hidden] { display: none; }

/* Main scroll area. Leaves room for the floating nav so content never hides
   behind it; honest-empty screens read comfortably. */
main.content {
  display: block;
  padding: 6px var(--gutter) calc(var(--nav-h) + env(safe-area-inset-bottom));
}
main.content.nonav { padding-bottom: 24px; }

/* ---- Identity chip -------------------------------------------------------- */
/* Avatar circle: filled with the member colour (--chip-bg), glyph recoloured to
   the colour's foreground (--chip-fg) via currentColor. Always paired with an
   accessible label (aria-label or a visible .chip-name) — never colour alone. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.av {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--chip-bg, var(--muted));
  color: var(--chip-fg, #fff);
}
.av svg { width: 60%; height: 60%; display: block; }
.av.sm { width: 24px; height: 24px; }
.av.lg { width: 38px; height: 38px; }
/* "none" variant — a dashed placeholder before a partner joins. */
.av.none {
  background: transparent;
  border: 1.5px dashed var(--placeholder);
  color: var(--muted);
}
.chip-name {
  font-size: 14px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* "both" variant — two overlapping avatars (the couple). */
.chip-both { display: inline-flex; align-items: center; }
.chip-both .av + .av { margin-left: -9px; border: 2px solid var(--surface); }

/* ---- Floating pill nav ---------------------------------------------------- */
.navwrap {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(14px + env(safe-area-inset-bottom));
  width: calc(min(100vw, var(--maxw)) - 24px);
  z-index: 20;
}
.nav {
  display: flex;
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--hairline);
  border-radius: 24px;
  box-shadow: var(--shadow-float);
  padding: 8px 6px;
}
.navtab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 8px 2px;
  border-radius: 16px;
  color: var(--muted);
  font-size: 10px;
  font-weight: 500;
  min-height: 44px;            /* real touch target */
  justify-content: center;
}
.navtab svg { width: 21px; height: 21px; }
.navtab[aria-current="page"] {
  background: var(--primary-tint);
  color: var(--primary);
  font-weight: 600;
}

/* ---- FAB ------------------------------------------------------------------ */
.fab {
  position: fixed;
  left: 50%;
  /* Pin to the right edge of the (max 480px) app column, lifted above the nav. */
  margin-left: calc(min(100vw, var(--maxw)) / 2 - 20px - 56px);
  bottom: calc(var(--nav-h) + 16px + env(safe-area-inset-bottom));
  width: 56px;
  height: 56px;
  border-radius: 18px;
  background: var(--primary);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  box-shadow: 0 10px 22px rgba(46, 156, 156, .44);
  z-index: 19;
}
.fab svg { width: 26px; height: 26px; }

/* ---- Cards / surfaces ----------------------------------------------------- */
.acard {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 13px 14px;
  margin-bottom: 12px;
  box-shadow: var(--shadow-raised);
}

/* ---- Empty state ---------------------------------------------------------- */
.empty {
  text-align: center;
  padding: 40px 18px;
  color: var(--muted);
}
.empty .ei { font-size: 30px; margin-bottom: 8px; }
.empty .et { font-size: 15px; font-weight: 600; color: var(--ink); margin-bottom: 4px; }
.empty .ed { font-size: 13.5px; line-height: 1.5; max-width: 260px; margin: 0 auto; }

/* ---- Buttons / inputs ----------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 0 18px;
  border-radius: 12px;
  border: 0;
  background: var(--primary);
  color: #fff;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
}
.btn.ghost {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--hairline);
}
.btn:disabled { opacity: .55; cursor: progress; }

input, textarea, select {
  font-family: inherit;
  font-size: 16px;          /* ≥16px — prevents iOS auto-zoom on focus */
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 12px;
  width: 100%;
}
input:focus-visible, textarea:focus-visible, select:focus-visible {
  border-color: var(--primary);
  outline: 2px solid var(--primary-tint);
}

/* ---- Errors --------------------------------------------------------------- */
/* Inline validation / page-level error (e.g. allowlist bounce on the Landing). */
.err {
  background: var(--alert-tint);
  color: var(--alert);
  border-radius: 10px;
  padding: 10px 13px;
  font-size: 13.5px;
  margin: 0 0 14px;
}
/* The same, sized for inside a sheet. */
.sheet-err {
  background: var(--alert-tint);
  color: var(--alert);
  border-radius: 9px;
  padding: 9px 12px;
  font-size: 12.5px;
  margin-bottom: 12px;
}

/* The global HTMX failed-save affordance (revealed by enhance.js on a network/
   5xx error). Hidden until then; a tap re-issues the same request. */
.retry-bar {
  display: none;
  align-items: center;
  gap: 10px;
  background: var(--alert-tint);
  color: var(--alert);
  border-radius: 10px;
  padding: 11px 13px;
  font-size: 13.5px;
  font-weight: 600;
  margin: 10px 0;
  width: 100%;
  text-align: left;
  border: 0;
  cursor: pointer;
}
.retry-bar.show { display: flex; }

/* ---- Bottom sheet --------------------------------------------------------- */
.sheet-scrim {
  position: fixed;
  inset: 0;
  background: rgba(31, 26, 26, .34);
  z-index: 29;
}
.sheet {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  width: 100%;
  max-width: var(--maxw);
  background: var(--surface);
  border-radius: 20px 20px 0 0;
  z-index: 30;
  padding: 8px var(--gutter) calc(20px + env(safe-area-inset-bottom));
  max-height: 86dvh;
  overflow: auto;
  box-shadow: 0 -10px 30px rgba(40, 30, 20, .22);
}
.sheet .grip {
  width: 38px;
  height: 4px;
  border-radius: 3px;
  background: var(--hairline);
  margin: 6px auto 12px;
}
.sheet-h {
  display: flex;
  align-items: center;
  font-size: 17px;
  font-weight: 700;
  margin: 0 2px 14px;
}
.sheet-h .st { flex: 1; }
.sheet-h .x {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  background: var(--canvas);
  border: 0;
  cursor: pointer;
}
/* Sheet body help text (e.g. the remove/clear confirm copy under the header). */
.sheet .field-help {
  font-size: 13.5px;
  color: var(--muted);
  margin: 0 2px 14px;
  line-height: 1.45;
}

/* ---- Landing (3-path, logged-out) ----------------------------------------- */
/* A standalone warm page (no nav). Centered card, reusing the shared tokens. */
.landing {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: 28px var(--gutter) calc(28px + env(safe-area-inset-bottom));
}
.landing-card { width: 100%; text-align: center; }
.landing-hero { font-size: 52px; line-height: 1; margin-bottom: 10px; }
.landing-h1 { font-size: 28px; font-weight: 700; margin: 0 0 6px; letter-spacing: -.3px; }
.landing-sub { font-size: 15.5px; color: var(--ink); margin: 0 0 4px; }
.landing-lead { font-size: 14px; color: var(--muted); margin: 0 auto 22px; max-width: 300px; }
.landing-actions { display: flex; flex-direction: column; gap: 10px; }
.landing-actions .btn { width: 100%; }
.landing-or {
  font-size: 12.5px;
  color: var(--muted);
  margin: 4px 0;
  text-transform: none;
}
.landing-fine { font-size: 12px; color: var(--muted); margin: 22px 0 0; }

/* ---- Streak hero ---------------------------------------------------------- */
/* The shared couple streak (one number, also on the Other tab). Warm butter
   gradient when live; a calm dashed day-0 state when the streak is 0 (honest
   "start your streak", never a fabricated count). */
.streak {
  display: flex;
  align-items: center;
  gap: 10px;
  border-radius: 13px;
  padding: 9px 13px;
  margin: 6px 0 12px;
  background: linear-gradient(135deg, #FBE9B8, #FBE7B0);
  border: 1px solid #F0DC95;
  box-shadow: 0 2px 6px rgba(180, 130, 30, .10);
}
.streak .fl {
  width: 30px; height: 30px;
  border-radius: 9px;
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; line-height: 1;
  background: rgba(255, 255, 255, .55);
  box-shadow: inset 0 0 0 1px rgba(180, 130, 30, .18);
}
.streak .st { flex: 1; min-width: 0; }
.streak .st .num { font-size: 14.5px; font-weight: 600; color: #7A5A12; }
.streak .st .num b { color: #C9791E; font-weight: 700; }
.streak.day0 {
  background: #F6F1E7;
  border: 1px dashed #D8CDB6;
  box-shadow: none;
}
.streak.day0 .fl {
  background: #EFE9DD;
  box-shadow: inset 0 0 0 1px #DDD2BC;
  filter: grayscale(1) opacity(.65);
}
.streak.day0 .st .num { color: var(--muted); font-weight: 600; }

/* ---- Joiner welcome strip (one-time) -------------------------------------- */
.welcome-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--primary-tint);
  color: #2f5a52;
  border-radius: 12px;
  padding: 11px 14px;
  font-size: 14px;
  margin: 4px 0 12px;
}

/* ---- Home greeting -------------------------------------------------------- */
.greet { margin: 0 2px 12px; }
.greet .hi { font-size: 19px; font-weight: 700; margin: 0 0 2px; letter-spacing: -.2px; }
.greet .dt { font-size: 13px; color: var(--muted); margin: 0; }

/* ---- Home widgets --------------------------------------------------------- */
/* A glanceable card linking to its feature. Honest-empty here: header + a soft
   prompt, no fabricated rows. Whole card is the tap target. */
.wdg {
  display: block;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 13px 14px;
  margin-bottom: 12px;
  box-shadow: var(--shadow-raised);
  color: inherit;
}
.wdg-h { display: flex; align-items: center; gap: 8px; }
.wdg-h .wt { font-size: 14.5px; font-weight: 700; }
.wdg-h .meta { flex: 1; text-align: right; font-size: 12.5px; color: var(--muted); }
.wdg-h .chev { flex: 0 0 auto; color: var(--placeholder); font-size: 18px; line-height: 1; }
.wdg-sub { font-size: 13px; color: var(--muted); margin: 7px 0 0; line-height: 1.45; }
/* Populated-widget mini-rows (Today): avatar chip + title + muted time.
   Mirrors the agenda .evt .t / .when pattern and the mockup .minirow. */
.wdg-rows { list-style: none; margin: 7px 0 0; padding: 0; }
.wdg-row { display: flex; align-items: center; gap: 9px; padding: 4px 0; }
.wdg-row-title {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.wdg-row-time { flex: 0 0 auto; font-size: 12px; color: var(--muted); text-align: right; }
/* The Due-today overdue flag — a word ("Overdue") / the "⚠ K overdue" subline.
   Colour is an enhancement on top of the text/⚠ symbol (never colour alone). */
.wdg-row-time.od { color: var(--alert); font-weight: 600; }
.wdg-sub.od { color: var(--alert); }

/* ---- Onboarding screens (join / invite / home-full) ----------------------- */
/* Standalone warm pages outside the shell (no nav). A single padded column. */
.onb {
  padding: 22px var(--gutter) calc(28px + env(safe-area-inset-bottom));
  min-height: 100dvh;
}
.onb-h1 { font-size: 22px; font-weight: 700; margin: 6px 0 14px; letter-spacing: -.2px; }
.onb-lead { font-size: 14.5px; color: var(--muted); margin: 0 0 16px; }
.onb-label { display: block; font-size: 13px; font-weight: 600; margin: 0 0 6px; }
.onb-fine { font-size: 12.5px; color: var(--muted); margin: 16px 0 0; }
.onb form input, .onb form select { margin-bottom: 12px; }

/* ---- Profile-setup pickers (avatar + colour) ------------------------------ */
/* Both pickers use a native radio hidden behind a tappable chip, with the
   selected state driven by :has(.…-radio:checked) — the same accessible,
   JS-free pattern as .chip-seg / .opts. A <fieldset>/<legend> gives each group
   an accessible name; the radios stay keyboard-native (arrow-key navigable). */
.pickset { border: 0; padding: 0; margin: 0 0 14px; min-width: 0; }
.pickset legend { padding: 0; }

/* Avatar: a wrap grid of avatar-circle chips. The hidden radio's :checked state
   rings the selected chip in the brand teal. The avatar glyph is shown neutral
   (the member colour is chosen separately below). */
.av-pick {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
.av-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 9px 4px;
  border: 1.5px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface);
  cursor: pointer;
  position: relative;
  min-height: 44px;
}
.av-radio { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
.av-opt .av {
  --chip-bg: #EEE8E0;
  --chip-fg: var(--ink);
}
.av-lbl { font-size: 11px; font-weight: 600; color: var(--muted); line-height: 1; }
.av-opt:has(.av-radio:checked) {
  border-color: var(--primary);
  background: var(--primary-tint);
}
.av-opt:has(.av-radio:checked) .av { --chip-bg: var(--primary); --chip-fg: #fff; }
.av-opt:has(.av-radio:checked) .av-lbl { color: var(--ink); }
.av-opt:has(.av-radio:focus-visible) {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Colour: a wrap grid of colour-swatch chips. The swatch shows the member
   colour; the selected chip reveals a contrast tick + a teal ring. */
.col-pick {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
.col-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 9px 4px;
  border: 1.5px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface);
  cursor: pointer;
  position: relative;
  min-height: 44px;
}
.col-radio { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
.col-swatch {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.col-tick { opacity: 0; }
.col-lbl { font-size: 11px; font-weight: 600; color: var(--muted); line-height: 1; }
.col-opt:has(.col-radio:checked) {
  border-color: var(--primary);
  background: var(--primary-tint);
}
.col-opt:has(.col-radio:checked) .col-tick { opacity: 1; }
.col-opt:has(.col-radio:checked) .col-lbl { color: var(--ink); }
.col-opt:has(.col-radio:focus-visible) {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Join: the valid-code confirmation + Google button. */
.validate-result { margin: 4px 0 0; }
.invite-confirm {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 11px 13px;
  margin: 4px 0 12px;
}
.invite-confirm .ic-text { font-size: 13.5px; margin: 0; line-height: 1.4; }
.gbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: var(--ink);
  font-size: 15.5px;
  font-weight: 600;
  box-shadow: var(--shadow-raised);
}
.gbtn .gg { width: 20px; height: 20px; flex: 0 0 auto; }

/* Invite & waiting: the code box, share row, regenerate. */
.invite-card { margin-bottom: 14px; }
.codebox {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 16px;
  text-align: center;
  margin-bottom: 12px;
  box-shadow: var(--shadow-raised);
}
.codebox .cl { font-size: 12.5px; color: var(--muted); margin: 0 0 6px; }
.codebox .code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: 3px;
  margin: 0;
  color: var(--ink);
}
.share-row { display: flex; gap: 10px; margin-bottom: 10px; }
.share-row .btn { flex: 1; min-height: 44px; font-size: 14.5px; }
.regen-row { text-align: center; margin-top: 10px; }
.linkbtn {
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 8px;
}
.regen-note { text-align: center; }
.openapp { width: 100%; margin-top: 14px; }

/* Partner-status poll: waiting + joined. */
.partner-status.waiting {
  display: flex;
  align-items: center;
  gap: 10px;
  background: #F3EFE9;
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 13.5px;
  color: var(--muted);
  margin-top: 14px;
}
.partner-status .spin {
  width: 16px; height: 16px;
  border: 2px solid #d8d0c5;
  border-top-color: var(--primary);
  border-radius: 50%;
  flex: 0 0 auto;
  animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.partner-status.joined {
  text-align: center;
  background: var(--primary-tint);
  border-radius: var(--radius);
  padding: 20px 16px;
  margin-top: 14px;
}
.partner-status.joined .joined-emoji { font-size: 38px; line-height: 1; margin-bottom: 6px; }
.partner-status.joined .joined-t { font-size: 17px; font-weight: 700; margin: 0 0 12px; }
.partner-status.joined .member-chips {
  display: flex;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.partner-status.joined .btn { width: 100%; }

/* ---- Calendar agenda (Task 3) --------------------------------------------- */
/* A day-grouped list (no month grid). Each .evt row is tinted by its assignee's
   colour, injected per-row as --evt-accent (resolved from COLORS — never
   hardcoded here), exactly like the identity chip. both/none fall back to a
   neutral accent so an unassigned/shared event still reads as a calm row. */
.daygroup {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--muted);
  text-transform: uppercase;
  margin: 16px 2px 8px;
}
#agenda > .daygroup:first-child { margin-top: 2px; }

.evt {
  display: flex;
  align-items: center;
  gap: 11px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-left: 4px solid var(--evt-accent, var(--placeholder));
  border-radius: var(--radius);
  padding: 11px 12px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-raised);
  color: var(--ink);
}
/* A faint wash of the assignee hue (member rows only carry --evt-accent). */
.evt.member {
  background:
    linear-gradient(0deg, color-mix(in srgb, var(--evt-accent) 7%, transparent),
                          color-mix(in srgb, var(--evt-accent) 7%, transparent)),
    var(--surface);
}
.evt.both { border-left-color: #BDB6AB; }
.evt.none { border-left-color: #DCD5CA; }
.evt .t { flex: 1; min-width: 0; }
.evt .t .ti {
  font-size: 15px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.evt .t .tm { font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.evt .chev { color: var(--placeholder); font-size: 19px; flex: 0 0 auto; }

/* The just-created row briefly glows, then settles (honours reduce-motion). */
.evt.just-added { animation: just-added-glow 1.6s ease-out 1; }
@keyframes just-added-glow {
  0%   { box-shadow: 0 0 0 2px var(--primary-tint); background: var(--primary-tint); }
  100% { box-shadow: var(--shadow-raised); }
}

/* Empty first-run: the CTA button + the solo invite nudge. */
.empty .evt-add { margin: 14px auto 0; }
.empty-nudge { margin: 12px 0 0; font-size: 13px; }
.empty-nudge a { color: var(--primary); font-weight: 600; }

/* ---- Event sheet form (Task 3) -------------------------------------------- */
.field { margin-bottom: 16px; }
.field > label,
.field .field-lbl {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 7px;
}
.field > label .req { color: var(--alert); }
/* .inp is the sheet's input style; it matches the global input rule but is named
   so the markup reads intentionally (and stays stable for the edit sheet). */
.inp { width: 100%; }

/* All-day toggle: a native checkbox whose :checked state CSS-hides the time
   fields — no JS, no round-trip (the constraint). The visible pill (.tg) mirrors
   the checkbox state via the sibling selector. */
.toggle-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0 2px;
  font-size: 14px;
  cursor: pointer;
}
.allday-toggle { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle-row .tg {
  margin-left: auto;
  width: 42px; height: 25px;
  border-radius: 13px;
  background: var(--placeholder);
  position: relative;
  flex: 0 0 auto;
  transition: background .15s;
}
.toggle-row .tg::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 21px; height: 21px;
  border-radius: 50%;
  background: #fff;
  transition: left .15s;
}
.allday-toggle:checked ~ .tg { background: var(--primary); }
.allday-toggle:checked ~ .tg::after { left: 19px; }
.allday-toggle:focus-visible ~ .tg { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Hide the time inputs when All-day is checked (CSS show/hide). */
.time-fields { display: flex; gap: 10px; margin-top: 14px; }
.time-fields .time-col { flex: 1; }
.allday-toggle:checked ~ .time-fields { display: none; }

/* "For whom" segmented avatar-only chips, backed by native radios. */
.chip-seg {
  display: flex;
  gap: 7px;
  background: #EEE8E0;
  border-radius: 12px;
  padding: 4px;
}
.chip-seg .cs {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  padding: 8px 4px;
  border-radius: 9px;
  cursor: pointer;
  position: relative;
}
.chip-seg .cs.ico { gap: 0; }
.cs-radio { position: absolute; opacity: 0; width: 0; height: 0; }
/* The selected chip (native :checked) gets the raised white pill.
   :has() is assumed (Baseline 2023 — covers our mobile target browsers). */
.chip-seg .cs:has(.cs-radio:checked) {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(40, 30, 20, .08);
}
.chip-seg .cs:has(.cs-radio:focus-visible) {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
.cs-name { line-height: 1; }

.assign-nudge {
  margin: 9px 0 0;
  font-size: 12px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 6px;
}
.assign-nudge a { color: var(--primary); font-weight: 600; }

.event-form .btn { width: 100%; margin-top: 4px; }

/* ---- Event detail (Task 4) ------------------------------------------------ */
/* The stable full page reached at /calendar/event/<id> (the Telegram reminder
   deep-link target). Reuses the shell; these add the back link, the "opened
   from your reminder" banner, the meta rows, the awareness caption + actions. */
.back-link { margin: 2px 0 10px; }
.back-link a {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 600;
}
.back-link svg { width: 18px; height: 18px; flex: 0 0 auto; }

/* The slim banner shown only when arriving via a Telegram reminder (?from=tg). */
.synced {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: #3c5a45;
  background: var(--primary-tint);
  border-radius: 8px;
  padding: 5px 11px;
  margin: 0 2px 12px;
}

/* The "updated by {partner}" awareness caption (last-write-wins, decision #3). */
.updated-by {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
  margin: 0 2px 14px;
  line-height: 1.4;
}
.updated-by .av { width: 17px; height: 17px; flex: 0 0 auto; }

/* The date / time / "for whom" rows. */
.detail-meta {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  color: #544e47;
  padding: 11px 0;
  border-bottom: 1px solid var(--hairline);
}
.detail-meta svg { width: 18px; height: 18px; color: var(--muted); flex: 0 0 auto; }
.detail-meta.whom { border-bottom: none; }
.detail-meta.whom .av { width: 22px; height: 22px; flex: 0 0 auto; }
.detail-meta .whom-lbl { margin-right: -2px; }

/* Edit (ghost) + Delete (danger) actions. */
.detail-actions { display: flex; gap: 10px; margin-top: 18px; }
.btn-ghost {
  border: 1px solid var(--primary);
  color: var(--primary);
  background: var(--surface);
  border-radius: 12px;
  padding: 12px;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.btn-danger {
  border: 1px solid var(--alert);
  color: var(--alert);
  background: var(--surface);
  border-radius: 12px;
  padding: 12px;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.detail-actions .btn-ghost,
.detail-actions .btn-danger { flex: 1; }

/* The edit sheet's inline Delete affordance (full width under the form). */
.sheet-delete { width: 100%; margin-top: 10px; }

/* The visually-hidden helper for screen-reader-only text. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---- To-do (Task 5) ------------------------------------------------------- */
/* The merged task feature: Habits (recurring) · Planned (one-offs) · Done.
   Recurring rows carry the single amber accent (a top strip via --recur); one-offs
   stay neutral. Identity is never colour alone — an owner avatar + a text label
   travel together (the owner avatar carries its own aria-label). */
:root { --recur: #E8843A; }

/* Segmented tab control (native links, enhanced by htmx). Mirrors .chip-seg's
   raised-pill-for-active treatment but full width with text labels. */
.seg.tabs {
  display: flex;
  gap: 6px;
  background: #EEE8E0;
  border-radius: 12px;
  padding: 4px;
  margin: 2px 0 14px;
}
.seg.tabs .s {
  flex: 1;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  padding: 8px 4px;
  border-radius: 9px;
  cursor: pointer;
}
.seg.tabs .s.on {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(40, 30, 20, .08);
}
.seg.tabs .s:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

/* Section labels (Due today / Overdue / Today / Upcoming / Someday / Paused …). */
.sec-lbl {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--muted);
  text-transform: uppercase;
  margin: 0 2px 8px;
}

/* The single success-rate line atop Habits (hidden entirely without history). */
.hstat { font-size: 13px; color: var(--muted); margin: 0 2px 12px; }
.hstat .pct { color: var(--primary); font-weight: 700; }

/* The row. A compact card; the recurring variant adds the amber top strip. */
.chore-row {
  display: flex;
  align-items: center;
  gap: 11px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 11px 12px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-raised);
  color: var(--ink);
  position: relative;
}
/* Recurring: the single amber accent — a thin full-width top strip. */
.chore-row.recur::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--recur);
}
.chore-row.recur { padding-top: 13px; }
/* Goal-driven recurring: a violet accent + the read-only lock. */
.chore-row.recur.goal::before { background: #8A6BD8; }
/* Coming-up (greyed) + paused rows read muted. */
.chore-row.upcoming, .chore-row.paused { opacity: .72; }

.chore-row .cinfo { flex: 1; min-width: 0; }
.chore-row .cn {
  font-size: 15px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chore-row .cn .lock { font-size: 12px; }
.chore-row .cc {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 2px;
}
.chore-row .cc .av { width: 18px; height: 18px; }
.chore-row .meta1 { font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.chore-row .row-owner { flex: 0 0 auto; }
.chore-row .when { font-size: 12.5px; color: var(--muted); flex: 0 0 auto; }
/* The overdue date flag (never colour alone — sits beside the "Overdue" label). */
.chore-row .od { color: var(--alert); font-weight: 600; }
/* The goal "managed elsewhere" pill (read-only — no Done affordance). */
.chore-row .goal-note {
  font-size: 11px;
  font-weight: 700;
  color: #6A4FB0;
  background: #F0EBFA;
  border-radius: 7px;
  padding: 3px 8px;
  flex: 0 0 auto;
}
/* The from-a-note origin tag. */
.origin-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  color: #8A6A3A;
  background: #F6EEDD;
  border-radius: 7px;
  padding: 2px 7px;
}

/* The goal-locked READ-ONLY edit sheet (source='goal' cook chore; §4.4 step 7).
   No form — just the title for context, the managed-by explainer, and a link to
   the owning goal. The lilac echoes the goal accent used on the rows. */
.goal-locked { padding: 4px 0 2px; }
.goal-locked-title {
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
  margin: 2px 0 12px;
}
.goal-locked-msg {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 14px;
  font-weight: 700;
  color: #6A4FB0;
  background: #F0EBFA;
  border-radius: 11px;
  padding: 11px 13px;
  margin: 0 0 10px;
}
.goal-locked-help {
  font-size: 13px;
  color: var(--muted);
  line-height: 1.45;
  margin: 0 0 16px;
}
.goal-open { display: inline-flex; }

/* Habits active-row actions: Done (primary) + Not-yet (ghost ✕). */
.chore-row .cdo { display: flex; gap: 7px; flex: 0 0 auto; }
.chore-row .done1 {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  font-weight: 600;
  color: #fff;
  background: var(--primary);
  border: 0;
  border-radius: 9px;
  padding: 7px 11px;
  cursor: pointer;
}
.chore-row .done1 svg { width: 15px; height: 15px; }
.chore-row .skip1 {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 9px;
  color: var(--muted);
  cursor: pointer;
}
.chore-row .skip1 svg { width: 15px; height: 15px; }

/* Planned one-off check + the Done-tab completed check. */
.chore-row .check {
  width: 22px; height: 22px;
  flex: 0 0 auto;
  border: 1.8px solid var(--placeholder);
  border-radius: 7px;
  background: var(--surface);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  color: var(--primary);
}
.chore-row .check svg { width: 14px; height: 14px; }
.chore-row.is-done .check {
  border-color: var(--primary);
  background: var(--primary-tint);
}
.chore-row.is-done .cn { color: var(--muted); }
/* Done recurring rows carry the compact amber dot. */
.chore-row.recur-done .check { border-color: var(--recur); color: var(--recur); }

/* The Done-tab header + the Clear-done affordance. */
.done-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--muted);
  text-transform: uppercase;
  margin: 0 2px 10px;
}
.done-head .clr {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--primary);
  background: none;
  border: 0;
  cursor: pointer;
  padding: 4px;
}

/* The just-done auto-replace confirmation pill ("Done ✓ · next: Sun"). */
.chore-row .next-pill {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 600;
  color: var(--primary);
  background: var(--primary-tint);
  border-radius: 8px;
  padding: 5px 9px;
  white-space: nowrap;
}

/* Inline Resume on a paused habit row. */
.chore-row .resume {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 600;
  color: var(--primary);
  background: var(--surface);
  border: 1px solid var(--primary);
  border-radius: 9px;
  padding: 7px 13px;
  cursor: pointer;
}

/* ---- To-do create/edit sheet (Task 6) ------------------------------------- */
/* The unified sheet's controls beyond the shared .field / .chip-seg / toggle:
   an in-sheet segmented radio control (Kind + cadence), the CSS show/hide blocks
   for One-off vs Repeats and the per-cadence params, and the weekday picker. */

/* In-sheet segmented control: native radios styled as a pill group (mirrors
   .seg.tabs, but each .s wraps a hidden radio so it posts + is keyboard-native). */
.field .seg {
  display: flex;
  gap: 6px;
  background: #EEE8E0;
  border-radius: 12px;
  padding: 4px;
}
.field .seg .s {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  padding: 8px 4px;
  border-radius: 9px;
  cursor: pointer;
  position: relative;
}
.seg-radio { position: absolute; opacity: 0; width: 0; height: 0; }
.field .seg .s:has(.seg-radio:checked) {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(40, 30, 20, .08);
}
.field .seg .s:has(.seg-radio:focus-visible) {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/* Kind show/hide: the toggle's :checked state reveals the matching block — no JS.
   The .kind-toggle holds the two radios; the blocks are its later siblings, so a
   sibling combinator keyed on the checked value drives visibility. */
.oneoff-block, .repeat-block { display: none; }
.kind-toggle:has(input[value="one_off"]:checked) ~ .oneoff-block { display: block; }
.kind-toggle:has(input[value="recurring"]:checked) ~ .repeat-block { display: block; }

/* Cadence params show/hide: the cadence segmented control reveals the interval
   stepper (Every-N) or the weekday picker (Weekly); Daily shows neither. */
.cad-every, .cad-weekly { display: none; }
.cadence-field:has(input[value="every_n_days"]:checked) ~ .cad-every { display: block; }
.cadence-field:has(input[value="weekly"]:checked) ~ .cad-weekly { display: block; }

/* The weekday multi-select (Mon..Sun) — checkboxes styled as toggle chips. */
.opts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.opts .opt {
  position: relative;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  background: #EEE8E0;
  border-radius: 9px;
  padding: 8px 11px;
  cursor: pointer;
}
.opt-check { position: absolute; opacity: 0; width: 0; height: 0; }
.opts .opt:has(.opt-check:checked) {
  background: var(--primary);
  color: #fff;
}
.opts .opt:has(.opt-check:focus-visible) {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/* The read-only from-a-note tag row inside the sheet. */
.origin-row { margin: -8px 2px 14px; }

.task-form .btn { width: 100%; margin-top: 4px; }

/* ---- Transient toast (Task 6) --------------------------------------------- */
/* A brief confirmation surfaced by a server `HX-Trigger: {"toast": …}` (e.g. a
   repeating task saved from Planned → "Added to Habits"). Above the nav, polite. */
.toast {
  position: fixed;
  left: 50%;
  bottom: 90px;
  transform: translateX(-50%) translateY(8px);
  max-width: min(420px, calc(100vw - 32px));
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 11px 15px;
  box-shadow: 0 6px 20px rgba(40, 30, 20, .14);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s, transform .18s;
  z-index: 60;
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ---- Shopping (the two-kind shared list) ---------------------------------- */
/* Ported from the v2 mockup gallery (§5 Shopping; `----- Shopping`,
   `Shopping · kind model`, `Shopping · staple edit/delete`). The inline add box,
   the per-row tick/name/quantity/added-by, the one-off butter accent, the
   per-tab tabhead, the partner-ping banner, and the CSS-only Edit toggle. */

/* The always-visible inline add box (no FAB — add is inline). */
.shop-add {
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 10px 12px;
  margin: 2px 0 8px;
}
.shop-add input {
  flex: 1;
  border: none;
  outline: none;
  font-size: 16px;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
}
.shop-add .addbtn {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--primary);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  cursor: pointer;
}
.shop-add .addbtn svg { width: 18px; height: 18px; }
/* Optional quantity input — narrow + secondary, sits beside the name input. */
.shop-add .qty {
  flex: 0 0 92px;
  font-size: 14px;
  color: var(--muted);
  border-left: 1px solid var(--hairline);
  padding-left: 10px;
}

/* Inline add-error slot — empty (collapsed) unless a 422 re-render fills it. */
.add-err { color: var(--alert); font-size: 13px; margin: 0 2px 12px; }
.add-err:empty { display: none; }

/* The per-tab head: a hint on the left, right-aligned action(s). */
.tabhead {
  display: flex;
  align-items: center;
  margin: 2px 2px 10px;
  font-size: 12.5px;
  color: var(--muted);
}
/* The hint's auto margin pushes the action(s) hard right — tag-agnostic, so the
   label-then-button order of Edit + Untick all doesn't matter. */
.tabhead .th-h { font-weight: 600; margin-right: auto; }
.tabhead .th-act {
  margin-left: 14px;
  color: var(--alert);
  font-weight: 600;
  background: none;
  border: none;
  font-size: 12.5px;
  font-family: inherit;
  cursor: pointer;
  padding: 2px 0;
}
.tabhead .th-act.untick { color: var(--primary); }
.tabhead .th-act:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* The CSS-only Edit toggle: the label text flips Edit → Done with the checkbox. */
.edit-toggle { color: var(--primary); }
.edit-toggle::after { content: "Edit"; }

/* The partner-ping banner (One-off add) — rendered above the list. */
.shop-ping {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--sage);
  font-weight: 600;
  background: #EAF2EC;
  border-radius: 9px;
  padding: 7px 11px;
  margin: 0 2px 12px;
}

/* One item row: a tick box, the name (+ optional quantity), the added-by avatar. */
.item {
  display: flex;
  align-items: center;
  gap: 11px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 11px 12px;
  margin-bottom: 8px;
}
.item .box {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  border: 2px solid #cfc7bb;
  background: var(--surface);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}
.item .box:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.item .nm { flex: 1; font-size: 15px; min-width: 0; }
.item .nm .q { color: var(--muted); font-size: 13px; margin-left: 5px; }
.item .row-owner { flex: 0 0 auto; }
/* Checked: sage tick + greyed, struck name (staples persist; one-offs are hidden
   from the list, so .checked only renders for staples in practice). */
.item.checked { background: #F6F3EE; }
.item.checked .box { background: var(--sage); border-color: var(--sage); }
.item.checked .box svg { width: 14px; height: 14px; color: #fff; }
.item.checked .nm { color: var(--muted); text-decoration: line-through; }
/* One-offs carry the butter paper left-accent. */
.item.oneoff { border-left: 3px solid var(--p-butter); }

/* Edit mode (Staples) — CSS-only, driven by the hidden #shop-edit checkbox that
   precedes .tabhead and .shop-list (so the ~ sibling combinator reaches both):
   the red .row-x remove handle shows and the tick .box hides. The label flips
   Edit → Done. No custom JS — mirrors the calendar all-day CSS toggle. */
.item .row-x {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--alert);
  color: #fff;
  border: none;
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}
.item .row-x svg { width: 14px; height: 14px; }
.shop-edit-cb:checked ~ .shop-list .row-x { display: flex; }
.shop-edit-cb:checked ~ .shop-list .box { display: none; }
.shop-edit-cb:checked ~ .tabhead .edit-toggle::after { content: "Done"; }

/* ===========================================================================
   GOALS (slice — Task 6): the hub goal-cards, the scenario tiles, the configure
   forms, and the per-kind detail screens. New design-system components defined
   here reuse the locked primitives (avatars, .seg, .field/.inp, .btn, .sheet) and
   add the goal-specific glance pieces (progress .bar, .weekdots, dual-stat,
   streak-flame, dinner-assign-row). NO Stars/badges/points (parked) — these are
   per-goal glances only.
   =========================================================================== */

/* ---- Hub header + empty/first-run ----------------------------------------- */
.goals-head { margin: 2px 0 12px; }
.goals-h { font-size: 19px; font-weight: 700; margin: 0; letter-spacing: -.2px; }

.goals-empty {
  text-align: center;
  padding: 22px 16px 18px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  box-shadow: var(--shadow-raised);
  margin-bottom: 16px;
}
.goals-empty .ge-glyph {
  width: 56px; height: 56px;
  margin: 0 auto 12px;
  display: flex; align-items: center; justify-content: center;
  font-size: 28px;
  border-radius: 16px;
  background: var(--primary-tint);
}
.goals-empty .ge-t { font-size: 17px; font-weight: 700; margin-bottom: 6px; }
.goals-empty .ge-sub {
  font-size: 13.5px; color: var(--muted); line-height: 1.5;
  max-width: 280px; margin: 0 auto 16px;
}
.goals-empty .ge-start { width: 100%; }

.quick-lbl { margin-top: 4px; }
.quick-tiles, .picker-tiles { display: flex; flex-direction: column; gap: 10px; }

/* ---- scenario-tile (catalog) ---------------------------------------------- */
.scenario-tile {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 12px 13px;
  box-shadow: var(--shadow-raised);
  color: var(--ink);
}
.scenario-tile .st-ico {
  flex: 0 0 auto;
  width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
  border-radius: 12px;
  background: var(--primary-tint);
}
.scenario-tile .st-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.scenario-tile .st-name { font-size: 15px; font-weight: 600; }
.scenario-tile .st-desc { font-size: 12.5px; color: var(--muted); line-height: 1.4; }
.scenario-tile .st-meta { font-size: 11.5px; color: var(--placeholder); }
.scenario-tile .st-chev { flex: 0 0 auto; color: var(--placeholder); font-size: 20px; line-height: 1; }
.scenario-tile .st-badge {
  flex: 0 0 auto;
  font-size: 11px; font-weight: 700;
  color: var(--primary);
  background: var(--primary-tint);
  border-radius: 999px;
  padding: 3px 9px;
}
.scenario-tile.is-active { border-color: var(--primary); }

.picker-foot { font-size: 12.5px; color: var(--muted); text-align: center; margin: 14px 0 0; }

/* ---- goal-card (kind-aware glance) ---------------------------------------- */
.goal-card {
  display: block;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 13px 14px;
  margin-bottom: 12px;
  box-shadow: var(--shadow-raised);
  color: var(--ink);
}
.goal-card.just-added { animation: justAdded 1.2s ease-out; }
@keyframes justAdded {
  0%   { box-shadow: 0 0 0 2px var(--primary-tint); }
  100% { box-shadow: var(--shadow-raised); }
}
.goal-card .gc-head { display: flex; align-items: center; gap: 9px; }
.goal-card .gc-ico { font-size: 18px; flex: 0 0 auto; }
.goal-card .gc-name { flex: 1; min-width: 0; font-size: 15px; font-weight: 600; }
.goal-card .gc-chev { flex: 0 0 auto; color: var(--placeholder); font-size: 19px; line-height: 1; }
.goal-card .gc-body { margin-top: 10px; }
.goal-card .gc-line {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 8px;
}
.goal-card .gc-pct { font-size: 13px; font-weight: 600; color: var(--primary); margin-right: auto; }
.goal-card .gc-big { font-size: 15px; font-weight: 700; }
.goal-card .gc-togo { font-size: 12.5px; color: var(--muted); }
.goal-card .gc-chips { display: inline-flex; align-items: center; gap: 5px; margin-left: auto; }
.goal-card .gc-num { font-size: 12.5px; font-weight: 600; color: var(--muted); }

/* ---- progress .bar (the shared metric bar) -------------------------------- */
.bar {
  height: 8px;
  border-radius: 999px;
  background: #EDE7DE;
  overflow: hidden;
}
.bar .bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--primary);
  transition: width .3s ease;
}

/* ---- .weekdots (a 7-dot week strip; decorative — truth is in the text) ----- */
.weekdots { display: flex; gap: 5px; margin-top: 8px; }
.weekdots .wd {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--hairline);
}
.weekdots .wd.on { background: var(--primary); }

/* ---- streak-flame (sm inline ONLY — the lg hero is the parked Us screen) ---- */
.streak-flame.sm {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 13px; font-weight: 700; color: #C9791E;
}
.streak-flame.sm .sf-fl { font-size: 13px; }

/* ---- dual-stat (two .stat cards, each top-bordered in the member colour) --- */
.dual-stat { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 4px 0 12px; }
.stat {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-top: 3px solid var(--blk, var(--primary));
  border-radius: var(--radius);
  padding: 12px;
  box-shadow: var(--shadow-raised);
}
.stat .stat-who { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.stat .stat-name { font-size: 12.5px; font-weight: 600; }
.stat .stat-big { font-size: 22px; font-weight: 700; line-height: 1.1; }
.stat .stat-big .stat-unit { font-size: 12px; font-weight: 600; color: var(--muted); }
.stat .stat-togo { font-size: 12.5px; color: var(--muted); margin-top: 2px; }

/* ---- .gline (cooperative encouragement one-liner) ------------------------- */
.gline {
  font-size: 13px; color: var(--muted);
  background: var(--primary-tint);
  border-radius: 12px;
  padding: 9px 12px;
  margin: 0 0 14px;
}

/* ---- .weigh / .mini-btn / .done-pill (log rows) --------------------------- */
.weigh-list { display: flex; flex-direction: column; gap: 9px; }
.weigh {
  display: flex; align-items: center; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 11px 12px;
  box-shadow: var(--shadow-raised);
}
.weigh .weigh-who { display: flex; align-items: center; gap: 7px; flex: 1; min-width: 0; }
.weigh .weigh-name { font-size: 13.5px; font-weight: 600; }
.weigh .weigh-stat { font-size: 13.5px; }
.weigh .weigh-stat .weigh-target { color: var(--muted); margin-left: 4px; }
.weigh .weigh-empty { color: var(--muted); }
.mini-btn {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 34px; padding: 0 14px;
  border-radius: 999px;
  background: var(--primary); color: #fff;
  border: 0;
  font-size: 13px; font-weight: 600;
  cursor: pointer;
}
.mini-btn.is-stub { background: var(--primary-tint); color: var(--primary); }
.done-pill {
  flex: 0 0 auto;
  font-size: 12.5px; font-weight: 600;
  color: var(--sage);
  background: color-mix(in srgb, var(--sage) 12%, var(--surface));
  border-radius: 999px;
  padding: 4px 10px;
}

/* ---- own-only inline weight log/edit row (Task 7) ------------------------- */
.weigh-log { margin: -2px 0 12px; }
.weigh-log .field-lbl { font-size: 12.5px; }
.weigh-log-row {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap;
}
.weigh-log-row .weigh-num { flex: 1 1 120px; min-width: 110px; width: auto; }
.weigh-log-row .unit-seg { flex: 0 0 auto; }
.weigh-log-row .mini-btn { flex: 0 0 auto; }

/* ---- goal lifecycle controls (pause / complete / abandon, Task 7) --------- */
.goal-lifecycle {
  display: flex; flex-direction: column; gap: 9px;
  margin: 20px 0 8px;
}
.goal-lifecycle .btn-ghost,
.goal-lifecycle .btn-danger { width: 100%; }
/* The cook "Edit plan" ghost link reads as a real button, not a stub. */
.cook-edit-link { display: block; width: 100%; margin: 4px 0 0; text-decoration: none; }

/* ---- weight chart card ----------------------------------------------------- */
.chart-card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 12px;
  margin: 6px 0 14px;
  box-shadow: var(--shadow-raised);
}

/* ---- configure forms ------------------------------------------------------- */
.cfg-h { display: flex; align-items: center; gap: 8px; margin: 6px 0 4px; }
.cfg-ico { font-size: 22px; }
.cfg-h1 { font-size: 21px; font-weight: 700; margin: 6px 0 14px; letter-spacing: -.2px; }
.cfg-h .cfg-h1 { margin: 0; }
.cfg-sub { font-size: 13.5px; color: var(--muted); line-height: 1.5; margin: 0 0 16px; }
.cfg-info {
  font-size: 12.5px; color: var(--muted);
  background: var(--canvas);
  border-radius: 12px;
  padding: 9px 12px;
  margin: 4px 0 16px;
}
.cfg-note { font-size: 12.5px; color: var(--muted); margin: -8px 0 16px; }
.cfg-start { width: 100%; }
.cfg-form { margin-top: 4px; }

/* Per-partner weight block (a card top-bordered in the member colour). */
.weight-block {
  border: 1px solid var(--hairline);
  border-top: 3px solid var(--blk, var(--primary));
  border-radius: var(--radius);
  padding: 12px 13px 14px;
  margin: 0 0 14px;
  background: var(--surface);
}
.weight-block legend {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13.5px; font-weight: 600;
  padding: 0 4px;
}
.weight-block .weight-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.weight-block .field { margin-bottom: 10px; }
.weight-block.disabled {
  border-top-color: var(--placeholder);
  background: var(--canvas);
  text-align: center;
}
.weight-block .blk-disabled-msg { font-size: 12.5px; color: var(--muted); margin: 4px 0; }
.unit-seg { max-width: 140px; }

/* The workout N stepper — revealed only when "A few times a week" is checked.
   The cadence radios live in .cadence-seg; the stepper field is a later sibling
   of that block within .cfg-form, so a :has() on the form reveals it. */
.field.npw-field { display: none; }
.cfg-form:has(.npw-radio .seg-radio:checked) .npw-field { display: block; }
.stepper { display: inline-flex; align-items: center; gap: 0; }
.stepper .step-btn {
  width: 40px; height: 40px;
  border: 1px solid var(--hairline);
  background: var(--surface);
  color: var(--ink);
  font-size: 20px; line-height: 1;
  cursor: pointer;
}
.stepper .step-btn:first-of-type { border-radius: 10px 0 0 10px; }
.stepper .step-btn:last-of-type { border-radius: 0 10px 10px 0; }
.stepper .step-val {
  width: 56px; height: 40px; text-align: center;
  border-radius: 0; border-left: 0; border-right: 0;
}

/* ---- dinner-assign-row (cook configure) ----------------------------------- */
.cook-divider {
  text-align: center; font-size: 11.5px; color: var(--placeholder);
  letter-spacing: .04em; margin: 4px 0 10px;
}
.cook-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.dinner-assign-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 8px 11px;
}
.dinner-assign-row .dar-day { flex: 1; font-size: 13.5px; font-weight: 600; }
.dinner-assign-row .dar-opts { display: inline-flex; gap: 5px; }
.dar-opt {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; min-height: 34px; padding: 2px 6px;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid transparent;
}
.dar-radio { position: absolute; opacity: 0; width: 0; height: 0; }
.dar-opt:has(.dar-radio:checked) { background: var(--primary-tint); border-color: var(--primary); }
.dar-opt:has(.dar-radio:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.dar-skip .dar-skip-lbl { font-size: 12px; color: var(--muted); }
.dar-opt:has(.dar-radio:checked) .dar-skip-lbl { color: var(--primary); font-weight: 600; }

.cook-helper {
  display: flex; align-items: center; gap: 6px;
  font-size: 12.5px; color: var(--muted);
  margin: 0 0 14px;
}
.cook-helper .ch-ico { color: var(--primary); }

/* ---- cook detail hero + plan ---------------------------------------------- */
.cook-hero {
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 16px;
  margin: 4px 0 14px;
  box-shadow: var(--shadow-raised);
}
.cook-hero .ch-big { font-size: 28px; font-weight: 700; line-height: 1.05; }
.cook-hero .ch-cap { font-size: 13px; color: var(--muted); margin-bottom: 12px; }
.cook-hero .bar { margin: 0 auto; max-width: 220px; }
.cook-hero .weekdots { justify-content: center; }
.cook-hero .cook-streak { font-size: 13px; font-weight: 600; color: #C9791E; margin: 10px 0 0; }

.success-banner {
  font-size: 13px;
  color: var(--sage);
  background: color-mix(in srgb, var(--sage) 12%, var(--surface));
  border-radius: 12px;
  padding: 10px 12px;
  margin: 0 0 14px;
}

.plan-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.minirow.plan-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 9px 12px;
}
.plan-row .pr-day { flex: 0 0 84px; font-size: 13px; font-weight: 600; }
.plan-row .pr-who { flex: 1; display: flex; align-items: center; gap: 6px; min-width: 0; }
.plan-row .pr-name { font-size: 13px; }
.plan-row .pr-status { flex: 0 0 auto; font-size: 12.5px; color: var(--muted); }
.plan-row.status-cooked .pr-status { color: var(--sage); font-weight: 600; }
.plan-row.status-tonight .pr-status { color: var(--primary); font-weight: 600; }

.cook-tonight { margin-bottom: 14px; }

/* ---- hub solo invite card -------------------------------------------------- */
.invite-card {
  display: flex; align-items: center; gap: 8px;
  border: 1.5px dashed var(--placeholder);
  border-radius: var(--radius);
  padding: 13px 14px;
  margin-top: 4px;
  font-size: 13px; color: var(--muted);
}
.invite-card .ic-arrow { margin-left: auto; color: var(--primary); font-weight: 700; }

/* The btn-ghost stub affordance reads as a static, non-interactive hint. */
.btn-ghost.is-stub { opacity: .65; display: inline-block; margin-top: 4px; }

/* ---- Fridge-door notes (Notes slice) -------------------------------------- */
/* Sticky-note cards on the door. The paper tone is server-fed as --paper (the
   PAPER_HEX map is the single source of truth — no tone hex lives here). All four
   tones keep the near-black ink (var(--ink), #1F1A1A) so body text stays AA on the
   paper; the rotation + tape are decorative only. */

/* A screen-reader-only label (the compose textarea label). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.notes-sub {
  margin: 0 2px 12px;
  font-size: 13.5px;
  color: var(--muted);
}

.notes-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.note-card {
  position: relative;
  background: var(--paper, var(--p-butter));
  color: var(--ink);
  border-radius: 14px;
  padding: 16px 16px 14px;
  box-shadow: 0 2px 6px rgba(40, 30, 20, .12);
}
/* A small deterministic decorative tilt by id parity (≤1.2deg so the ink never
   leans far). Disabled under reduce-motion via the global rule below. */
.note-card[data-tilt="a"] { transform: rotate(-1.2deg); }
.note-card[data-tilt="b"] { transform: rotate(1deg); }

/* Unread (partner's, not yet acked) → a teal ring. NEVER colour alone: the
   visible "Got it" button + the li aria-label carry the meaning too. */
.note-card.unread {
  box-shadow: 0 0 0 2px var(--primary), 0 2px 6px rgba(40, 30, 20, .12);
}

/* Faint faux "tape" strip top-center — decorative paper detail. */
.nc-tape {
  position: absolute;
  top: -7px;
  left: 50%;
  transform: translateX(-50%) rotate(-1deg);
  width: 54px;
  height: 14px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .5);
  box-shadow: inset 0 0 0 1px rgba(40, 30, 20, .06);
}

.note-card .nc-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.note-card .nc-who { font-size: 13px; font-weight: 600; }
.note-card .nc-time { margin-left: auto; font-size: 11.5px; color: var(--muted); }

.note-card .nc-body {
  margin: 0 0 12px;
  font-size: 15px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.note-card .nc-foot { display: flex; align-items: center; gap: 8px; }
/* "On the board ✓" cross-link tag — quiet, sits left; the receipt pushes right. */
.note-card .nc-onboard { font-size: 12px; white-space: nowrap; }
.note-card .nc-ack {
  min-height: 40px;
  padding: 0 16px;
  margin-left: auto;
  font-size: 14px;
}
.note-card .nc-receipt { margin-left: auto; font-size: 12.5px; }
.note-card .nc-receipt.muted { color: var(--muted); }
.note-card .nc-receipt.seen { color: var(--sage); font-weight: 600; }

/* Newest-card entrance on a post-create re-render (reuse the glow keyframes). */
.note-card.just-added { animation: just-added-glow 1.6s ease-out 1; }

/* The solo "notes are better shared" dashed invite card under the empty state. */
.note-invite {
  background: var(--surface);
  border: 1.5px dashed var(--placeholder);
  box-shadow: none;
  margin-top: 18px;
  transform: none;
  text-align: center;
}
.note-invite .ni-msg { margin: 0; font-size: 13px; color: var(--muted); }
.note-invite .ni-msg a { color: var(--primary); font-weight: 600; }

/* The empty door glyph (no base .empty .eg rule exists). */
.notes-empty .eg { font-size: 34px; margin-bottom: 8px; }
.notes-empty .btn { margin-top: 14px; }

/* ---- Compose sheet (note-compose) ----------------------------------------- */
/* You write directly on the paper: the textarea sits on the selected tone. The
   swatch radios live-recolour the paper via CSS :has() (a progressive nicety; the
   server already pre-paints --paper for the no-:has fallback). */
.note-compose-form { display: flex; flex-direction: column; }

.note-paper-write {
  position: relative;
  background: var(--paper, var(--p-butter));
  border-radius: 14px;
  padding: 18px 14px 10px;
  margin-bottom: 14px;
  box-shadow: 0 2px 6px rgba(40, 30, 20, .12);
}
.np-text {
  width: 100%;
  min-height: 110px;
  resize: vertical;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: 16px;
  line-height: 1.5;
  padding: 0;
}
.np-text:focus-visible { outline: none; }
.np-text::placeholder { color: rgba(31, 26, 26, .42); }
.np-count {
  text-align: right;
  font-size: 11.5px;
  color: rgba(31, 26, 26, .55);
  margin-top: 4px;
}
/* Warn near the cap (enhance/JS sets --over when close; CSS-only fallback below). */
.np-count.near { color: var(--alert); font-weight: 600; }

.np-swatches {
  display: flex;
  gap: 12px;
  align-items: center;
  border: 0;
  padding: 0;
  margin: 0 0 16px;
}
.np-swatch { position: relative; cursor: pointer; }
.np-swatch input {
  position: absolute; opacity: 0; width: 0; height: 0;
}
.np-swatch .np-dot {
  display: block;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: inset 0 0 0 1px rgba(40, 30, 20, .12);
}
.np-swatch input:checked ~ .np-dot {
  box-shadow: 0 0 0 2px var(--primary), inset 0 0 0 1px rgba(40, 30, 20, .12);
}
.np-swatch input:focus-visible ~ .np-dot {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
/* Live-recolour the paper from the checked swatch where :has() is supported (the
   server-painted --paper is the fallback for older engines). Order maps the four
   swatches to the four tones via :nth-of-type. */
.note-compose-form:has(.np-swatch:nth-of-type(1) input:checked) .note-paper-write { --paper: #FCF3C9; }
.note-compose-form:has(.np-swatch:nth-of-type(2) input:checked) .note-paper-write { --paper: #FBE2E2; }
.note-compose-form:has(.np-swatch:nth-of-type(3) input:checked) .note-paper-write { --paper: #DDEBF7; }
.note-compose-form:has(.np-swatch:nth-of-type(4) input:checked) .note-paper-write { --paper: #DCEFE0; }

.np-todo { margin-bottom: 16px; }
.note-compose-form .btn { width: 100%; }

/* ---- The door header (subtitle + Bin link) -------------------------------- */
.notes-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.notes-head .notes-sub { margin-bottom: 12px; }
.bin-link {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  min-height: 28px;
  display: inline-flex;
  align-items: center;
}
.bin-link:hover { color: var(--ink); }

/* Author-only edit ✎ + "take down" ✕ on your own card. Subtle ghost buttons; the
   edit opens the compose sheet in edit mode, the delete (→ the Bin) has a confirm.
   The edit sits left of the delete; .nc-edit drops the left margin so the pair
   nestles together after the time. */
.note-card .nc-edit,
.note-card .nc-del {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  margin: -4px -4px -4px 4px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: rgba(31, 26, 26, .42);
}
.note-card .nc-edit { margin-left: 0; }
.note-card .nc-edit:hover,
.note-card .nc-del:hover { color: var(--ink); background: rgba(40, 30, 20, .06); }

/* ---- The Bin (soft-deleted notes) ----------------------------------------- */
.bin-back {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  min-height: 28px;
  display: inline-flex;
  align-items: center;
}
.bin-back:hover { color: var(--ink); }
/* Binned cards read as set-aside: muted, flat, no decorative tilt. */
.note-card.binned {
  opacity: .82;
  box-shadow: var(--shadow-raised);
  transform: none;
}
.note-card.binned .nc-foot { align-items: center; }
.note-card .nc-restore { min-height: 36px; margin-left: auto; font-size: 13px; }

/* ---- The once-per-session sticker (note-sticker) -------------------------- */
/* A raised sticky-note "magnet" that drops in below the top bar, inset 16px,
   rotated ~ -2deg, overlaying content (absolute → doesn't push layout). Sits
   inside .app (position: relative). Below the floating nav/FAB (z 19/20), above
   page content. */
.note-sticker {
  position: absolute;
  top: calc(env(safe-area-inset-top) + 60px);
  left: 16px;
  right: 16px;
  z-index: 18;
  display: flex;
  align-items: flex-start;
  gap: 6px;
  padding: 14px 12px 12px;
  border-radius: 14px;
  background: var(--p-butter);
  color: var(--ink);
  transform: rotate(-2deg);
  box-shadow: 0 8px 22px rgba(40, 30, 20, .22);
  /* The drop-in: translateY -12px + rotate 0→-2deg + fade ~220ms. */
  animation: sticker-drop 220ms ease-out 1;
}
.note-sticker .nc-tape { top: -7px; }
.ns-card {
  flex: 1 1 auto;
  display: block;
  color: inherit;
  min-width: 0;
}
.ns-head { display: flex; align-items: center; gap: 8px; }
.ns-who { font-size: 13.5px; font-weight: 600; }
.ns-who strong { font-weight: 700; }
.ns-teaser {
  margin: 6px 0 4px;
  font-size: 14px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}
.ns-open { font-size: 12.5px; font-weight: 600; color: var(--primary); }
.ns-x {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  margin: -10px -6px 0 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: rgba(31, 26, 26, .5);
}
.ns-x:hover { color: var(--ink); background: rgba(40, 30, 20, .08); }

@keyframes sticker-drop {
  from { opacity: 0; transform: translateY(-12px) rotate(0deg); }
  to { opacity: 1; transform: translateY(0) rotate(-2deg); }
}

/* Reduce-motion: drop the decorative card tilt + entrance (the global rule already
   neutralises animation/transition durations; flatten the static rotation too). */
@media (prefers-reduced-motion: reduce) {
  .note-card[data-tilt="a"],
  .note-card[data-tilt="b"] { transform: none; }
  /* The sticker keeps its static -2deg rotation (decorative, AA-safe); the global
     rule already zeroes the drop-in animation so it fades only. */
}

/* ===========================================================================
   GIFTS (slice — Task 4): wishlists + shared savings goals.
   Two sections on one page. Reuses .acard / .bar / .empty / .fab / .field /
   .inp / .sheet from the design system; only the gift-specific shapes live here.
   =========================================================================== */

/* ---- section scaffold ----------------------------------------------------- */
.gifts { padding-bottom: 8px; }
.gift-section { margin: 0 0 26px; }
.gift-section + .gift-section { margin-top: 8px; }
.gift-section-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.gift-section-h {
  font-size: 17px;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 12px;
}
.closed-link { font-size: 13px; color: var(--muted); font-weight: 600; }
.closed-link:hover { color: var(--primary); }

/* ---- wishlist segments ---------------------------------------------------- */
.wish-seg { margin-bottom: 18px; }
.wish-seg-h {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
  margin: 0 0 9px;
}
/* Two-up grid of photo-forward cards; collapses to one column on the narrowest. */
.wish-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
@media (max-width: 360px) { .wish-grid { grid-template-columns: 1fr; } }
.wish-empty { padding: 22px 12px; }
.wish-empty .ei { font-size: 26px; }

/* ---- wishlist card -------------------------------------------------------- */
.wishlist-card {
  margin-bottom: 0;          /* the grid gap owns the spacing */
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* Fixed-aspect cover slot: the photo (Task 6) or a neutral placeholder. */
.wc-cover {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--primary-tint);
  display: flex;
  align-items: center;
  justify-content: center;
}
.wc-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.wc-ph { color: var(--placeholder); }
.wc-ph svg { width: 34px; height: 34px; }
.wc-given {
  position: absolute;
  top: 8px; right: 8px;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--sage);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(40, 30, 20, .25);
}
.wc-body { padding: 10px 12px 12px; }
.wc-name { font-size: 14.5px; font-weight: 600; color: var(--ink); margin: 0; line-height: 1.3; }
.wc-price { font-size: 13px; font-weight: 700; color: var(--primary); margin: 3px 0 0; }
.wc-note { font-size: 12.5px; color: var(--muted); margin: 5px 0 0; line-height: 1.4; }
.wc-url { font-size: 12.5px; color: var(--primary); font-weight: 600; display: inline-block; margin-top: 6px; }
.wc-given-by {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--sage);
  font-weight: 600;
  margin: 8px 0 0;
}
/* Given state: the cover dims + the name softens (no strike — warm, not deleted). */
.wishlist-card.given .wc-cover { opacity: .55; }
.wishlist-card.given .wc-name { color: var(--muted); }

/* Create-confirmation glow — reuses the shared keyframe (matches .evt / .note-card). */
.wishlist-card.just-added { animation: just-added-glow 1.6s ease-out 1; }

/* ---- "gifts are better shared" invite card (solo) ------------------------- */
.invite-card {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  border: 1.5px dashed var(--placeholder);
  border-radius: var(--radius);
  padding: 14px 16px;
  background: transparent;
}
.invite-card .ic-ico { font-size: 20px; }
.invite-card .ic-txt { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.invite-card .ic-cta { font-size: 13.5px; font-weight: 700; color: var(--primary); margin-left: auto; }

/* ---- savings card --------------------------------------------------------- */
.savings-card { padding: 14px 15px; }
.sc-top { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; }
.sc-ico { font-size: 19px; line-height: 1; }
.sc-title { font-size: 15px; font-weight: 700; color: var(--ink); margin-right: auto; }
.sc-badge {
  font-size: 12px;
  font-weight: 700;
  color: var(--primary);
  background: var(--primary-tint);
  border-radius: 999px;
  padding: 3px 9px;
  white-space: nowrap;
}
.sc-badge.reached { color: var(--sage); background: #E6F0E9; }
.savings-card.reached { border-color: #CDE3D4; }
.sc-bar { margin-bottom: 8px; }
.savings-card.reached .sc-bar .bar-fill { background: var(--sage); }
.sc-nums { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.sc-saved { font-size: 15px; font-weight: 700; color: var(--ink); }
.sc-of { font-size: 12.5px; color: var(--muted); }
.sc-togo { font-size: 12.5px; color: var(--muted); margin-left: auto; }
.sc-over { font-size: 12.5px; color: var(--sage); font-weight: 600; margin-left: auto; }
.sc-chips { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 11px; }
.sc-chip { display: inline-flex; align-items: center; gap: 6px; }
.sc-chip-amt { font-size: 12.5px; font-weight: 600; color: var(--muted); }
.savings-empty { padding: 26px 14px; }

/* ---- the second (savings) FAB --------------------------------------------- */
/* A secondary pill FAB pinned just above the primary wishlist FAB. It carries a
   label so two stacked actions stay distinguishable; the primary stays the round
   ＋ for "add to my wishlist". */
.fab-savings {
  width: auto;
  height: 44px;
  border-radius: 999px;
  padding: 0 16px 0 13px;
  gap: 7px;
  background: var(--ink);
  /* Lift above the primary FAB (which sits at nav-h + 16px, 56px tall). */
  bottom: calc(var(--nav-h) + 16px + 56px + 12px + env(safe-area-inset-bottom));
  /* Right-align with the primary FAB's right edge. */
  margin-left: calc(min(100vw, var(--maxw)) / 2 - 20px - 56px);
  box-shadow: var(--shadow-float);
}
.fab-savings svg { width: 18px; height: 18px; }
.fab-savings .fab-lbl { font-size: 13.5px; font-weight: 600; color: #fff; white-space: nowrap; }

/* ---- gift compose sheets -------------------------------------------------- */
.gift-compose .opt { font-weight: 400; color: var(--muted); font-size: 12.5px; }
/* Active photo upload affordance (Task 6) — a label-styled file picker. The
   native <input type=file> is visually hidden; the dashed label is the target. */
.gc-photo { margin-bottom: 16px; }
.gc-photo-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  border: 1.5px dashed var(--placeholder);
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  padding: 14px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.gc-photo-btn:hover { border-color: var(--primary); color: var(--primary); }
.gc-photo-btn svg { width: 22px; height: 22px; }
/* Visually-hidden file input (the label is the click target); a chosen file's
   focus ring still reaches the label via :focus-within. */
.gc-photo-input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.gc-photo:focus-within .gc-photo-btn { border-color: var(--primary); color: var(--primary); }
.gc-soon {
  margin-left: auto;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--muted);
  background: var(--hairline);
  border-radius: 999px;
  padding: 2px 8px;
}
/* Money input: a leading currency glyph inside the field. */
.gc-money { position: relative; }
.gc-cur {
  position: absolute;
  left: 13px; top: 50%;
  transform: translateY(-50%);
  font-size: 16px;
  color: var(--muted);
  pointer-events: none;
}
.gc-price { padding-left: 26px; }
/* Optional icon picker — native radios, the chosen glyph highlights. */
.gc-icons { display: flex; flex-wrap: wrap; gap: 8px; }
.gc-icon { position: relative; cursor: pointer; }
.gc-icon input { position: absolute; opacity: 0; width: 0; height: 0; }
.gc-icon > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  border-radius: 12px;
  border: 1px solid var(--hairline);
  background: var(--surface);
  font-size: 20px;
}
.gc-icon:has(input:checked) > span {
  border-color: var(--primary);
  background: var(--primary-tint);
}
.gc-icon:has(input:focus-visible) > span {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}
/* Contribute sheet: the Adjust hint under the amount field. */
.gc-hint { font-size: 12px; color: var(--muted); margin: 7px 0 0; line-height: 1.4; }
.gc-hint code {
  background: var(--hairline);
  border-radius: 5px;
  padding: 0 4px;
  font-size: 11.5px;
}

/* ===========================================================================
   GIFTS (slice — Task 5): the per-card action affordances + the closed archive.
   The wishlist/savings cards gain a footer action row; the closed archive lists
   muted "done" goals. Reuses the design-system .btn/.bar shapes; only the
   gift-specific action shapes live here.
   =========================================================================== */

/* ---- wishlist card actions ------------------------------------------------ */
.wc-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}
/* The primary text action (Mark as given / Undo) takes the left, pushing the
   owner icon actions to the right. */
.wc-act {
  flex: 1 1 auto;
  min-height: 34px;
  padding: 0 11px;
  border-radius: 9px;
  border: 1px solid var(--primary);
  background: var(--primary-tint);
  color: var(--primary);
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}
.wc-act.ghost {
  border-color: var(--hairline);
  background: var(--surface);
  color: var(--muted);
}
/* Owner-only square icon actions (edit / delete). */
.wc-icon-act {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  border: 1px solid var(--hairline);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}
.wc-icon-act:hover { color: var(--ink); border-color: var(--placeholder); }

/* ---- savings card actions ------------------------------------------------- */
.sc-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 13px;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
}
.sc-act {
  min-height: 36px;
  padding: 0 13px;
  border-radius: 9px;
  border: 1px solid var(--primary);
  background: var(--primary);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
}
.sc-act.ghost {
  border-color: var(--hairline);
  background: var(--surface);
  color: var(--ink);
}
.sc-icon-act {
  margin-left: auto;
  width: 36px; height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  border: 1px solid var(--hairline);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}
.sc-icon-act:hover { color: var(--ink); border-color: var(--placeholder); }

/* ---- the closed archive --------------------------------------------------- */
.gifts-sub { margin: 0 0 14px; }
.closed-list { display: flex; flex-direction: column; gap: 12px; }
.savings-card.closed { opacity: .82; }
.savings-card.closed .sc-title { color: var(--muted); }
.sc-badge.done {
  color: var(--sage);
  background: #E6F0E9;
}
.sc-closed-when { font-size: 12.5px; color: var(--muted); margin: 8px 0 0; }
.savings-card.closed .sc-actions {
  border-top: 0;
  padding-top: 8px;
  margin-top: 8px;
}

/* ---- Home "Saving together" widget (populated) ---------------------------- */
.wdg-savings-title { margin: 8px 0 7px; font-weight: 600; }
.wdg-savings-bar { margin-bottom: 7px; }

/* ---- Notifications: the re-link banner (worker slice, Task 5) ------------- */
/* A gentle, full-width nudge under the header when Telegram isn't connected.
   Tappable → /profile (the connect card). Quiet primary-tint, never alarming. */
.relink-banner {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 8px var(--gutter) 0;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--primary-tint);
  border: 1px solid var(--hairline);
  color: var(--ink);
  text-decoration: none;
  font-size: 13.5px;
}
.relink-ico { font-size: 16px; line-height: 1; }
.relink-txt { flex: 1; font-weight: 500; }
.relink-go { color: var(--primary); font-size: 18px; font-weight: 600; }

/* ---- Notifications: the in-app bell feed ---------------------------------- */
.bell { margin-bottom: 18px; }
.bell-list { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: 8px; }
.bell-item {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 12px 14px;
  font-size: 14px;
  line-height: 1.45;
  box-shadow: var(--shadow-raised);
}
.bell-item.bell-muted { opacity: .7; }
.bell-link { color: var(--ink); text-decoration: none; display: block; }
.bell-link:hover { color: var(--primary); }
.bell-txt { color: var(--ink); display: block; }

/* ---- Notifications: the Telegram connect card ----------------------------- */
.tg-connect {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 18px;
  box-shadow: var(--shadow-raised);
}
.tg-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; }
.tg-ico { font-size: 20px; line-height: 1.1; }
.tg-h { font-size: 15px; font-weight: 600; margin: 0; color: var(--ink); }
.tg-sub { font-size: 13px; color: var(--muted); margin: 2px 0 0; }
.tg-sub.tg-ok { color: var(--sage); }
.tg-step { font-size: 13.5px; color: var(--ink); margin: 0 0 8px; }
.tg-open { width: 100%; margin-bottom: 10px; }
.tg-link-hint { font-size: 12.5px; color: var(--muted); margin: 0 0 4px; }
.tg-link {
  display: block;
  word-break: break-all;
  font-size: 12px;
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 8px 10px;
  color: var(--muted);
}
.tg-reissue { margin-top: 8px; }
.btn-link {
  background: none;
  border: 0;
  padding: 0;
  color: var(--primary);
  font: inherit;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
}

/* ---- Notifications: the per-category Telegram toggles --------------------- */
.bell-prefs-h { font-size: 15px; font-weight: 600; margin: 0 0 2px; color: var(--ink); }
.bell-prefs-sub { font-size: 13px; color: var(--muted); margin: 0 0 10px; }
.pref-rows {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-raised);
}
.pref-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 14px;
  border-top: 1px solid var(--hairline);
  cursor: pointer;
}
.pref-row:first-child { border-top: 0; }
.pref-lbl { flex: 1; font-size: 14px; color: var(--ink); }
.pref-locked { font-size: 12px; color: var(--muted); }
.pref-toggle { width: 20px; height: 20px; accent-color: var(--primary); }
.pref-toggle:disabled { accent-color: var(--placeholder); cursor: default; }
