/* app.css — Upkeep. Apple-minimal, modern. White, airy, system type.
   Grouped inset lists (iOS-style), hairline rules, one restrained blue for
   interactive state, black pills for primary actions, category colors as marks. */

:root {
  /* surfaces */
  --bg: #ffffff;             /* cards, inputs — float on the canvas */
  --canvas: #f2f2f6;         /* app background */
  --surface: #e7e8ee;        /* control tracks, secondary fills (darker than canvas) */
  --surface-press: #dddee6;

  /* ink */
  --ink: #1d1d1f;            /* primary text */
  --ink-2: #6e6e73;          /* secondary text (>=4.5:1 on white) */
  --ink-3: #8a8a8e;          /* tertiary / placeholder-strength */

  /* lines */
  --line: rgba(0, 0, 0, .10);
  --line-2: rgba(0, 0, 0, .16);

  /* interactive — pine: the owned brand accent (calm, cared-for), not stock blue */
  --accent: #0b6e54;         /* links, focus, selection */
  --accent-press: #095942;
  --accent-soft: rgba(11, 110, 84, .12);

  /* status (text-grade on white) */
  --danger: #d70015;
  --danger-soft: rgba(215, 0, 21, .08);
  --warn: #9a5b00;
  --warn-soft: rgba(154, 91, 0, .09);
  --ok: #1d7a3e;
  --ok-soft: rgba(29, 122, 62, .10);

  /* radii */
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-pill: 980px;

  /* elevation (soft, sparse) */
  --shadow-fab: 0 6px 20px rgba(0, 0, 0, .16);
  --shadow-pop: 0 12px 40px rgba(0, 0, 0, .18);
  --shadow-card: 0 1px 2px rgba(17, 24, 39, .04), 0 4px 14px rgba(17, 24, 39, .05);
  --shadow-raise: 0 2px 6px rgba(17, 24, 39, .06), 0 10px 28px rgba(17, 24, 39, .09);

  --maxw: 600px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bot: env(safe-area-inset-bottom, 0px);

  /* z-scale */
  --z-fab: 20;
  --z-toast: 60;

  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
          "Segoe UI", system-ui, Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* The UA rule for [hidden] is `display: none` at zero specificity, so ANY author `display` — a
   `.nav-stack { display: flex }`, a grid, an inline-flex button — silently wins and the element
   stays on screen. Every `el.hidden = true` in the app depends on this holding. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font);
  background: var(--canvas);
  color: var(--ink);
  line-height: 1.45;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100dvh;
  /* App-like touch: kill the double-tap-to-zoom (and its 300ms delay) so tapping buttons/rows never
     zooms the page. Panning/scrolling and the custom swipe/pull gestures are unaffected. Pinch and
     input-focus zoom are handled by the locked viewport scale in app.html. */
  touch-action: manipulation;
}

#app { max-width: var(--maxw); margin: 0 auto; }

/* slim, unobtrusive scrollbars */
* { scrollbar-width: thin; scrollbar-color: rgba(0, 0, 0, .22) transparent; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, .2); border-radius: 8px;
  border: 3px solid var(--bg); background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, .34); background-clip: padding-box; border: 3px solid var(--bg); }
::-webkit-scrollbar-corner { background: transparent; }

.screen {
  padding: calc(24px + var(--safe-top)) 20px calc(56px + var(--safe-bot));
  min-height: 100dvh;
  position: relative;
  overflow-x: clip; /* contain the ambient wash bleed; no horizontal scroll */
}

/* the dashboard supplies no screen padding of its own — the hero band bleeds to the
   edges and the body provides its own padding below. */
.dash { padding: 0 0 calc(40px + var(--safe-bot)); }

/* full-bleed hero band — a deep, mood-colored surface anchoring the top of the screen.
   This is the brand moment: color carries the home's state, it isn't decoration. */
.hero-band {
  position: relative;
  padding: calc(26px + var(--safe-top)) 20px 28px;
  border-radius: 0 0 28px 28px;
  color: #fff;
  background: var(--band);
}
.dash[data-mood="ok"]      { --band: linear-gradient(165deg, #0f5440, #0a3b2d); }
.dash[data-mood="neutral"] { --band: linear-gradient(165deg, #0f5440, #0a3b2d); }
.dash[data-mood="soon"]    { --band: linear-gradient(165deg, #5a4111, #3a2a0a); }
.dash[data-mood="overdue"] { --band: linear-gradient(165deg, #5c1d1f, #3a1214); }

.dash-body { padding: 22px 20px 0; }

/* invert the chrome inside the dark band (beat the later .masthead rules on specificity) */
.hero-band .masthead .home-kicker { color: rgba(255, 255, 255, .60); }
.hero-band .masthead .home-name { color: #fff; }
.hero-band .standfirst { color: #fff; margin: 16px 0 0; }
.hero-band .standfirst .count,
.hero-band .standfirst .count.ok,
.hero-band .standfirst .count.danger,
.hero-band .standfirst .count.warn { color: #fff; }
.hero-band .standfirst .sub { color: rgba(255, 255, 255, .72); }
.hero-band .icon-btn {
  background: rgba(255, 255, 255, .14); color: #fff;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.hero-band .icon-btn:hover { background: rgba(255, 255, 255, .24); }

::selection { background: var(--accent-soft); }

/* ---------- typography scale (fixed, product-grade) ---------- */
h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.022em; line-height: 1.12; text-wrap: balance; }
h2 { font-size: 1.3125rem; font-weight: 650; letter-spacing: -0.018em; line-height: 1.2; text-wrap: balance; }
h3 { font-size: 1.0625rem; font-weight: 600; letter-spacing: -0.012em; }
h4 { font-size: 1.0625rem; font-weight: 600; letter-spacing: -0.012em; }

.lede { color: var(--ink-2); font-size: 1.0625rem; line-height: 1.4; }
.fine { color: var(--ink-2); font-size: .8125rem; line-height: 1.4; }
.fine.credit { margin-top: 36px; text-align: center; color: var(--ink-3); }
.muted-note { color: var(--ink-2); font-size: .9375rem; }

/* ---------- top bars ---------- */
.top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 22px; min-height: 36px;
}
.top .mid { flex: 1; text-align: center; font-size: 1.0625rem; font-weight: 600; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.spacer { width: 64px; flex: 0 0 64px; }

/* Sticky detail header: on a long detail/setup screen the nav bar pins to the top so the way out
   stays reachable and — once the big title scrolls under it — the item's name rides in .mid, so you
   never lose track of what you're editing. The negative top margin cancels the screen's top padding
   so the bar can pin flush; its own padding restores the safe-area inset. */
.screen.detail > .top {
  position: sticky; top: 0; z-index: 20;
  margin-top: calc(-1 * (24px + var(--safe-top)));
  padding-top: calc(12px + var(--safe-top)); padding-bottom: 12px;
  margin-bottom: 14px;
  background: var(--canvas);
  border-bottom: 1px solid transparent; transition: border-color .2s ease;
}
.screen.detail > .top.stuck { border-bottom-color: var(--line); }
/* the name in the nav bar: hidden until the big title leaves, so it never doubles up at the top */
.top .mid.name-mid {
  opacity: 0; transform: translateY(4px);
  transition: opacity .2s ease, transform .2s ease;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.top .mid.name-mid.show { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .top .mid.name-mid { transition: opacity .12s ease; transform: none; }
}

/* a saved link, tappable straight from a field's label (Purchase link, etc.) */
.field-open { float: right; font-size: .8125rem; font-weight: 600; color: var(--accent); text-decoration: none; display: inline-flex; align-items: center; gap: 3px; }
.field-open svg { width: 13px; height: 13px; }
.field-open[hidden] { display: none; }
.field-open:hover { color: var(--accent-press); }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--surface); border: none; color: var(--ink);
  cursor: pointer; flex: 0 0 auto;
  transition: background .15s ease, transform .1s ease;
}
.icon-btn:hover { background: var(--surface-press); }
.icon-btn:active { transform: scale(.94); }
.icon-btn svg { width: 19px; height: 19px; }

.link {
  background: none; border: none; color: var(--accent); cursor: pointer;
  font: inherit; font-size: 1.0625rem; font-weight: 500; letter-spacing: -0.01em;
  padding: 6px 2px; display: inline-flex; align-items: center; gap: 3px;
  border-radius: 8px;
}
.link:hover { color: var(--accent-press); }
.link.strong { font-weight: 600; }
.link.back svg { width: 17px; height: 17px; margin-left: -4px; }
.link.danger { color: var(--danger); display: block; margin: 28px auto 0; font-size: 1rem; }
.link.danger:hover { color: var(--danger); opacity: .8; }

/* Touch targets. Several controls are drawn smaller than a finger: the row tick (30px),
   the care toggle (46x28), the stock stepper (34x32), header icon buttons (38px). The
   drawn size is deliberate, so instead of resizing them we grow only the TAPPABLE area
   to 44px (Apple HIG 44pt / Material 48dp) with a centered pseudo-element. This changes
   no layout and no pixel — it just stops near-misses on the app's most-used actions.
   Gaps were checked so no expanded area overlaps a neighbouring control. */
/* .pw-eye is already absolutely positioned, so it is its own containing block — listing it
   here would only add a declaration that loses to its own rule below. */
.tick, .switch, .step-btn, .part-del, .icon-btn, .link.back, .inv-reset, .cmp-dot { position: relative; }
.tick::after, .switch::after, .step-btn::after, .part-del::after,
.icon-btn::after, .link.back::after, .inv-reset::after, .cmp-dot::after, .pw-eye::after {
  content: ''; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 100%; height: 100%; min-width: 44px; min-height: 44px;
}
.link:focus-visible, .icon-btn:focus-visible, .btn:focus-visible {
  outline: 3px solid var(--accent-soft); outline-offset: 1px;
}

/* ---------- dashboard masthead + standfirst ---------- */
.dash-top { align-items: flex-start; margin-bottom: 4px; }
.masthead { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.masthead .home-kicker {
  font-size: .8125rem; font-weight: 600; color: var(--ink-3);
  letter-spacing: -0.005em; text-transform: none;
}
.masthead .home-name {
  font-size: 1.3125rem; font-weight: 650; letter-spacing: -0.02em; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.top-actions { display: flex; gap: 8px; flex: 0 0 auto; }

/* the hero: one confident status sentence owns the top of the screen */
.standfirst {
  font-size: clamp(2.1rem, 9vw, 2.6rem); font-weight: 700; letter-spacing: -0.032em;
  line-height: 1.04; margin: 14px 0 22px; text-wrap: balance; color: var(--ink);
}
.standfirst .count { display: inline; }
.standfirst .count.danger { color: var(--danger); }
.standfirst .count.warn { color: var(--warn); }
.standfirst .count.ok { color: var(--accent); }
.standfirst .sub {
  display: block; font-size: 1.0625rem; font-weight: 500; color: var(--ink-2);
  letter-spacing: -0.012em; line-height: 1.35; margin-top: 8px;
}

/* ---------- group label ---------- */
.group {
  display: flex; align-items: baseline; gap: 8px;
  font-size: .8125rem; font-weight: 600; color: var(--ink-2);
  letter-spacing: 0; margin: 26px 4px 10px;
}
.group .n { color: var(--ink-3); font-weight: 500; }
.group:first-of-type { margin-top: 4px; }

/* ---------- grouped inset list ---------- */
.list {
  background: var(--bg); border-radius: 16px; overflow: hidden;
  box-shadow: var(--shadow-card);
}
.list + .list { margin-top: 12px; }

.row {
  display: flex; align-items: center; gap: 14px;
  padding: 15px 16px; position: relative; background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.row:last-child { border-bottom: none; }
/* button rows (nav / manage hub / appliance list): no hard tap outline, soft ring on keyboard only */
button.row { -webkit-tap-highlight-color: transparent; }
button.row:focus { outline: none; }
button.row:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: -3px; }

/* ---------- task row ---------- */
.task-row { padding-right: 12px; transition: background .14s ease; }
.task-row:active { background: color-mix(in srgb, var(--ink) 4%, transparent); }
.task-row .body { flex: 1; min-width: 0; cursor: pointer; }
.task-cat { display: inline-flex; align-items: center; gap: 6px; font-size: .8125rem; font-weight: 600; color: var(--ink-2); letter-spacing: -0.005em; }
.task-cat .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; background: var(--ink-3); }

/* category icon chip — tinted square in the category color (iOS-style) */
.cat-ico {
  display: inline-grid; place-items: center; flex: 0 0 auto;
  width: 24px; height: 24px; border-radius: 7px;
  background: color-mix(in srgb, currentColor 18%, transparent);
}
.cat-ico svg { width: 14px; height: 14px; display: block; }
.cat-ico.lead {
  width: 42px; height: 42px; border-radius: 13px;
  background: color-mix(in srgb, currentColor 16%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 12%, transparent);
}
.cat-ico.lead svg { width: 22px; height: 22px; }
.cat-ico.lg { width: 36px; height: 36px; border-radius: 11px; }
.cat-ico.lg svg { width: 20px; height: 20px; }

.task-row h4 { margin: 0 0 3px; font-size: 1.0625rem; letter-spacing: -0.014em; }
.task-sub { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; font-size: .9375rem; color: var(--ink-2); }
.task-sub .sep { color: var(--ink-3); }
/* descriptor can be a user-named subject (a pet/appliance/vehicle), not just a short category —
   let it shrink and ellipsize on its line rather than wrapping oddly across several. */
.cat-name { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-due { font-size: .9375rem; color: var(--ink-2); }
/* overdue / soon get a real status pill, not just colored text — a clear visual language */
.task-row.overdue .task-due,
.task-row.soon .task-due {
  font-weight: 600; font-size: .8125rem; letter-spacing: -0.005em;
  padding: 2px 9px; border-radius: var(--r-pill); line-height: 1.3;
}
.task-row.overdue .task-due { color: var(--danger); background: var(--danger-soft); }
.task-row.soon .task-due { color: var(--warn); background: var(--warn-soft); }
.task-row.overdue .task-sub .sep:first-of-type,
.task-row.soon .task-sub .sep:first-of-type { display: none; }
.task-meta { margin-top: 7px; display: flex; gap: 10px; flex-wrap: wrap; }
.who-chip { display: inline-flex; align-items: center; gap: 6px; font-size: .8125rem; color: var(--ink-2); }

/* complete control — the satisfying tick */
.tick {
  flex: 0 0 30px; width: 30px; height: 30px; border-radius: 50%;
  border: 1.8px solid var(--line-2); background: var(--bg); cursor: pointer;
  display: grid; place-items: center; color: transparent;
  transition: background .18s ease, border-color .18s ease, transform .12s ease, color .18s ease;
}
.tick svg { width: 16px; height: 16px; }
.tick:hover { border-color: var(--accent); color: color-mix(in srgb, var(--accent) 45%, transparent); }
.tick:active { transform: scale(.88); }
.tick.done { background: var(--accent); border-color: var(--accent); color: #fff; }

@keyframes rowLeave { to { opacity: 0; transform: translateX(8px); height: 0; padding-top: 0; padding-bottom: 0; } }
.row.leaving { animation: rowLeave .32s cubic-bezier(.4, 0, .2, 1) forwards; overflow: hidden; }

/* ---------- avatar ---------- */
.ava {
  flex: 0 0 auto; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); color: var(--ink); font-weight: 600;
  width: 22px; height: 22px; font-size: .72rem;
}
.ava.lg { width: 36px; height: 36px; font-size: .95rem; }

/* ---------- empty state ---------- */
.empty {
  text-align: center; padding: 56px 24px; color: var(--ink-2);
  border: 1px dashed var(--line-2); border-radius: var(--r-md);
}
.empty .glyph { font-size: 1.8rem; margin-bottom: 12px; opacity: .7; }
.empty-title { color: var(--ink); font-weight: 600; font-size: 1.0625rem; margin-bottom: 6px; }

/* the primary "add" action lives in the header (.top-actions), not a floating button —
   a floating circle is the dated Material idiom this app deliberately avoids. */

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border-radius: var(--r-pill); border: 1px solid transparent;
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 1.0625rem; font-weight: 600; letter-spacing: -0.01em;
  padding: 12px 22px; cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background .15s ease, transform .1s ease, opacity .15s ease, border-color .15s ease;
}
.btn:hover { background: var(--surface-press); }
.btn:active { transform: scale(.98); }
.btn.primary { background: var(--ink); color: #fff; }
.btn.primary:hover { background: #000; }
.btn.ghost { background: transparent; border-color: var(--line-2); color: var(--ink); }
.btn.ghost:hover { background: var(--surface); }
.btn.small { padding: 8px 16px; font-size: .9375rem; }
.btn.big { width: 100%; padding: 15px; font-size: 1.0625rem; margin-top: 8px; }
.btn.buy { background: var(--accent); color: #fff; }
.btn.buy:hover { background: var(--accent-press); }
/* task action link (pay / renew / file) — the generalized buy-link, pine like Buy */
.btn.action { background: var(--accent); color: #fff; }
.btn.action:hover { background: var(--accent-press); }
.btn.action svg { width: 17px; height: 17px; opacity: .85; }
.btn[disabled] { opacity: .45; pointer-events: none; }
.btn svg { width: 18px; height: 18px; }

/* ---------- forms ---------- */
.field { display: block; margin-bottom: 18px; }
.field > span, .field > legend { display: block; font-size: .9375rem; font-weight: 500; color: var(--ink-2); margin-bottom: 7px; }
.field input, .field select, .field textarea, .assign-select {
  width: 100%; background-color: var(--bg); border: 1px solid var(--line-2); color: var(--ink);
  border-radius: var(--r-md); padding: 14px 15px; font: inherit; font-size: 1.0625rem;
  line-height: 1.4;
  transition: border-color .15s ease, box-shadow .15s ease;
  -webkit-appearance: none; appearance: none;
}
.field textarea { resize: vertical; min-height: 64px; }
/* Date inputs are normalized globally, further down ("date & time inputs"). The old fix lived here,
   scoped to `.field` and missing type="month" — which is why the appliance "Purchased" field rendered
   as a short empty pill next to a full-height select. */
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }

/* password field with a show/hide eye */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 48px; }
.pw-eye { position: absolute; top: 50%; right: 6px; transform: translateY(-50%); display: inline-grid; place-items: center; width: 38px; height: 38px; border: none; background: none; color: var(--ink-3); cursor: pointer; border-radius: 9px; }
.pw-eye:hover { color: var(--ink-2); }
.pw-eye:active { background: var(--surface); }
.pw-eye svg { width: 20px; height: 20px; }
.auth-forgot { display: block; margin: 14px auto 0; }
.pw-caps { display: block; margin-top: 6px; font-size: .8125rem; font-weight: 600; color: var(--warn); }
.pw-caps[hidden] { display: none; }
.field input:focus, .field select:focus, .field textarea:focus, .assign-select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft);
}
select.field, .field select, .assign-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%236e6e73' stroke-width='1.6' stroke-linecap='round'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 15px center; background-size: 12px;
  padding-right: 38px;
}

/* selects — make them feel deliberate, not flat */
.field select, .assign-select { cursor: pointer; font-weight: 500; }
.field select:hover, .assign-select:hover { border-color: var(--ink-3); background-color: var(--surface); }

/* ---------- grouped form (new / edit task) ----------
   Inset white cards with hairline-separated rows, matching the app's list idiom —
   not a flat stack of fields floating on the canvas. */
.form-label {
  display: flex; align-items: baseline; gap: 8px;
  font-size: .8125rem; font-weight: 600; color: var(--ink-2);
  margin: 26px 4px 10px; letter-spacing: 0;
}
.form-label .opt { color: var(--ink-3); font-weight: 500; }

.form-group {
  background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card);
  padding: 0 16px; margin-bottom: 4px;
}
.form-group:not(.sched) .field {
  margin: 0; padding: 15px 0; border-bottom: 1px solid var(--line);
}
.form-group:not(.sched) .field:last-child { border-bottom: none; }
.form-group .field > span { margin-bottom: 8px; }
.form-group .field .hint { color: var(--ink-3); font-weight: 400; }

/* inputs sit on a faint canvas fill so they read against the white card */
.form-group .field input,
.form-group .field textarea,
.form-group .select-btn {
  background-color: var(--canvas); border-color: transparent;
}
.form-group .field input:focus,
.form-group .field textarea:focus,
.form-group .select-btn:focus-visible {
  background-color: var(--bg); border-color: var(--accent);
}
.form-group .select-btn:hover { background: var(--surface); border-color: transparent; }

/* schedule group is one logical block, not hairline rows */
.form-group.sched { padding: 16px; }
.form-group.sched .mode-seg { margin-bottom: 14px; }
.form-group.sched .unit-seg { margin-bottom: 0; }
.form-group.sched .recur-row { margin-bottom: 12px; }
.form-group.sched .sched-last { margin: 16px 0 0; }
.form-group.sched .sched-first { margin: 14px 0 0; }
.form-group.sched .once-date { margin-bottom: 8px; }
.form-group.sched .field input { background-color: var(--canvas); border-color: transparent; }
.form-group.sched .field input:focus { background-color: var(--bg); border-color: var(--accent); }

/* live next-reminder readout — the payoff of the schedule + last-done inputs */
.next-due {
  display: flex; align-items: center; gap: 7px;
  margin: 12px 0 0; padding: 11px 13px;
  background: var(--accent-soft); color: var(--accent);
  border-radius: var(--r-sm); font-size: .9375rem; font-weight: 600; letter-spacing: -0.01em;
}
.next-due::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto;
}
.next-due.muted {
  background: var(--surface); color: var(--ink-2);
  font-weight: 500; line-height: 1.35; align-items: flex-start;
}
.next-due.muted::before { margin-top: 6px; background: var(--ink-3); }

/* custom select trigger (replaces native <select>) */
.select-btn {
  width: 100%; display: flex; align-items: center; gap: 10px;
  background: var(--bg); border: 1px solid var(--line-2); color: var(--ink);
  border-radius: var(--r-md); padding: 14px 15px; font: inherit; font-size: 1.0625rem; font-weight: 500;
  cursor: pointer; text-align: left;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.select-btn:hover { border-color: var(--ink-3); background: var(--surface); }
.select-btn:active { background: var(--surface-press); }
.select-btn:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.select-btn .sel-val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.select-btn .sel-chev { display: inline-flex; color: var(--ink-3); flex: 0 0 auto; }
.select-btn .sel-chev svg { width: 18px; height: 18px; }

/* bottom-sheet picker */
.sheet-backdrop {
  position: fixed; inset: 0; background: rgba(0, 0, 0, .34); z-index: 90;
  opacity: 0; transition: opacity .24s ease; -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.sheet-backdrop.show { opacity: 1; }
.sheet {
  position: fixed; left: 50%; bottom: 0; transform: translate(-50%, 100%);
  width: 100%; max-width: var(--maxw); z-index: 91;
  background: var(--bg); border-radius: 22px 22px 0 0;
  padding: 8px 14px calc(18px + var(--safe-bot));
  box-shadow: 0 -12px 44px rgba(0, 0, 0, .2);
  transition: transform .28s cubic-bezier(.22, 1, .36, 1);
  max-height: 80vh; display: flex; flex-direction: column;
}
.sheet.show { transform: translate(-50%, 0); }
.sheet-grab { width: 38px; height: 4px; border-radius: 4px; background: var(--line-2); margin: 6px auto 12px; }
.sheet-title { font-size: .8125rem; font-weight: 600; color: var(--ink-2); padding: 0 6px 6px; }
.sheet-list { overflow-y: auto; display: flex; flex-direction: column; }
.sheet-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: none; border: none; border-bottom: 1px solid var(--line); cursor: pointer;
  font: inherit; font-size: 1.0625rem; color: var(--ink); padding: 15px 6px; text-align: left;
}
.sheet-opt:last-child { border-bottom: none; }
.sheet-opt:hover { background: var(--surface); }
.sheet-opt:active { background: var(--surface-press); }
.sheet-opt.on { color: var(--accent); font-weight: 600; }
.opt-label { display: inline-flex; align-items: center; gap: 11px; min-width: 0; }
.opt-dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; }
.sheet-check { display: inline-flex; color: var(--accent); flex: 0 0 auto; }
.sheet-check svg { width: 18px; height: 18px; }

@media (prefers-reduced-motion: reduce) {
  .sheet { transition: none; }
  .sheet-backdrop { transition: none; }
}

/* lock the page behind an open sheet — otherwise the sheet and the page both scroll (double bar) */
html.scroll-locked, html.scroll-locked body { overflow: hidden; }

/* task quick-look peek (expandable content sheet) */
.content-sheet { padding: 0 20px calc(20px + var(--safe-bot)); }
/* overscroll-behavior:none (not just contain) so a downward drag at the top hands cleanly to the
   dismiss gesture instead of rubber-banding the scroll container first. */
.content-sheet.expandable { max-height: 92vh; overflow-y: auto; overscroll-behavior: none; }
/* Collapsed, the peek fits without scrolling — kill scroll/rubber-band so a drag anywhere on
   the sheet moves it (instead of the browser stealing the gesture for a scroll). */
.content-sheet.expandable:not(.expanded) { overflow: hidden; touch-action: none; }
/* sticky, full-width grab handle: always reachable to drag-collapse, and it hides content
   scrolling underneath. The visible pill is the ::after; the whole strip is the drag target. */
.content-sheet .sheet-grab {
  position: sticky; top: 0; z-index: 3;
  margin: 0 -20px 6px; padding: 16px 0 12px;   /* generous touch target for drag-to-collapse */
  background: var(--bg); border-radius: 22px 22px 0 0;
  display: grid; place-items: center; width: auto; height: auto;
  cursor: grab; touch-action: none;
}
.content-sheet .sheet-grab::after { content: ''; width: 40px; height: 4px; border-radius: 4px; background: var(--line-2); }
.content-sheet .sheet-grab:active { cursor: grabbing; }

.peek { padding-top: 2px; }
.peek-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.peek-head .detail-cat { margin-bottom: 4px; }
.peek-edit { flex: 0 0 auto; padding: 2px 2px; }
/* title reuses the app's h1 token (the task name is this view's title) — no one-off size */
.peek-title { margin: 6px 0 4px; }
.peek .detail-due { margin-bottom: 4px; }
.peek .detail-note { margin: 10px 0 4px; }
.peek .btn.big { margin-top: 16px; }
.peek .btn.action.big { margin-top: 10px; }

.peek-section { margin-top: 20px; }
.peek-h { font-size: .8125rem; font-weight: 600; color: var(--ink-2); margin-bottom: 8px; }
.peek-section .protype { padding: 0; }

/* drag affordance — only while collapsed */
.drag-hint {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  margin-top: 18px; color: var(--ink-3); font-size: .875rem; font-weight: 500;
}
.drag-hint svg { width: 16px; height: 16px; }
.content-sheet.expanded .drag-hint { display: none; }

/* expanded-only content reveals on drag-up (bottom-anchored sheet grows upward).
   Animate a grid row 0fr -> 1fr so the sheet grows to the details' REAL height on a single
   continuous ease — like sliding a drawer up. (The old max-height:1600px overshot the ~300px of
   content, so the box snapped to full height in ~70ms and then just faded copy in: a cut, not a
   glide.) The inner wrapper needs min-height:0 + overflow:hidden for the row to actually collapse. */
.expanded-only {
  display: grid; grid-template-rows: 0fr; opacity: 0;
  /* steady, near-constant-velocity glide (responsive from frame 1, gentle settle) so the reveal
     reads like scrolling the drawer up — not an aggressive decelerate that pops then settles. */
  transition: grid-template-rows .42s cubic-bezier(.25, .1, .35, 1), opacity .34s ease;
}
.expanded-inner { min-height: 0; overflow: hidden; }
.content-sheet.expanded .expanded-only { grid-template-rows: 1fr; opacity: 1; }
@media (prefers-reduced-motion: reduce) { .expanded-only { transition: opacity .2s ease; } }

/* install instructions sheet (iOS / fallback add-to-home) */
.install-help { text-align: center; padding: 6px 0 4px; }
.install-icon { width: 72px; height: 72px; border-radius: 17px; box-shadow: var(--shadow-card); }
.install-title { font-size: 1.375rem; font-weight: 700; letter-spacing: -.01em; color: var(--ink); margin: 14px 0 6px; }
.install-sub { font-size: .9375rem; line-height: 1.45; color: var(--ink-2); max-width: 34ch; margin: 0 auto; }
.install-steps {
  text-align: left; margin: 20px 0 4px;
  border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden;
}
.install-step {
  font-size: 1.0625rem; line-height: 1.5; color: var(--ink);
  padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.install-step:last-child { border-bottom: none; }
.install-step strong { font-weight: 600; }
.install-key { font-weight: 600; color: var(--accent); white-space: nowrap; }
.install-key svg { width: 18px; height: 18px; vertical-align: -4px; }
.install-help .btn.big { margin-top: 18px; }

/* recurrence (count + unit) */
.recur { display: flex; gap: 10px; }
.recur input { flex: 0 0 104px; }
.recur select { flex: 1; }
.recur-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.recur-row .recur-prefix { font-size: 1.0625rem; color: var(--ink-2); }
/* the count input styles itself (no longer inherits .field ancestry after the regroup) */
.recur-row input {
  width: 96px; background: var(--canvas); border: 1px solid transparent; color: var(--ink);
  border-radius: var(--r-md); padding: 12px 14px; font: inherit; font-size: 1.0625rem; font-weight: 600;
  -webkit-appearance: none; appearance: none; -moz-appearance: textfield;
  transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.recur-row input:focus {
  outline: none; background: var(--bg); border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft);
}
.recur-row input::-webkit-outer-spin-button,
.recur-row input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.seg.inline { margin-bottom: 12px; }
.unit-seg .seg-btn, .mode-seg .seg-btn { font-size: .9rem; }
.link[disabled] { opacity: .4; pointer-events: none; }

/* ---------- finder: search + filter chips ---------- */
.finder { margin-bottom: 12px; }
/* search + filter chips share one row; focusing search expands it and collapses the chips */
.finder-row { display: flex; align-items: center; }

/* (The old dashboard search field lived here. It's now the shared .mf field in the masthead —
   see "Manage finder". The .finder row below is filter chips only.) */

/* filter chips share the finder row with search and collapse away while searching */
.finder-chips {
  display: flex; gap: 8px; flex: 0 0 auto; margin-left: 8px;
  overflow: hidden; max-width: 62vw; opacity: 1;
  transition: max-width .3s cubic-bezier(.32, .72, 0, 1), opacity .2s ease, margin .3s ease;
}

/* filter chips — filled, borderless, tactile; active tints pine with a category color dot. */
.chip {
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; flex: 0 0 auto;
  background: var(--surface); border: none; color: var(--ink);
  font: inherit; font-size: .9375rem; font-weight: 600; letter-spacing: -0.01em;
  padding: 9px 15px; border-radius: var(--r-pill); cursor: pointer;
  transition: background .15s ease, color .15s ease, transform .1s ease;
}
.chip:hover { background: var(--surface-press); }
.chip:active { transform: scale(.95); }
.chip:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 1px; }
.chip.on { background: var(--accent-soft); color: var(--accent-press); }
.chip .chip-chev { display: inline-flex; opacity: .5; margin-right: -3px; }
.chip .chip-chev svg { width: 15px; height: 15px; }
.chip .chip-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.chip.clear { background: transparent; color: var(--accent); }
.chip.clear:hover { background: var(--accent-soft); }

.results-head { font-size: .8125rem; font-weight: 600; color: var(--ink-2); margin: 20px 4px 10px; }

/* ---------- runway time dividers (Next in line) ---------- */
.runway-divider {
  font-size: .8125rem; font-weight: 600; color: var(--ink-3);
  margin: 16px 4px 8px; letter-spacing: -0.005em;
}

/* ---------- caught-up hero (empty Due soon) ---------- */
.caught-up {
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 2px;
  padding: 28px 24px; margin-top: 2px;
  background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card);
}
.cu-check {
  display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%;
  background: var(--ok-soft); color: var(--ok); margin-bottom: 8px;
}
.cu-check svg { width: 22px; height: 22px; }
.cu-title { font-size: 1.0625rem; font-weight: 600; color: var(--ink); }
.cu-sub { font-size: .9375rem; color: var(--ink-2); }

/* ---------- first-run: start fresh card ---------- */
.startfresh {
  background: var(--bg); border-radius: 18px; box-shadow: var(--shadow-raise);
  border: 1px solid var(--line); padding: 22px 20px; margin-bottom: 24px;
}
.sf-title { margin-bottom: 6px; }
.sf-body { color: var(--ink-2); font-size: .9375rem; line-height: 1.45; margin-bottom: 18px; max-width: 60ch; }

/* two honest framings — recessed wells on the card, not nested cards */
.sf-choices { display: grid; gap: 12px; }
.sf-choice { background: var(--canvas); border-radius: 14px; padding: 16px; }
.sf-choice-h { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.sf-choice-ic {
  display: inline-grid; place-items: center; flex: 0 0 auto;
  width: 28px; height: 28px; border-radius: 8px;
  background: var(--bg); color: var(--accent);
}
.sf-choice-ic svg { width: 17px; height: 17px; }
.sf-choice-t { font-weight: 650; font-size: 1rem; letter-spacing: -0.01em; }
.sf-choice-d { color: var(--ink-2); font-size: .875rem; line-height: 1.45; margin: 0 0 14px; }
.sf-choice .btn.big { margin-top: 0; }

/* ---------- set up section (never-done pool) ---------- */
.setup-sect > summary { list-style: none; cursor: pointer; }
.setup-sect > summary::-webkit-details-marker { display: none; }
.setup-sum { display: flex; align-items: center; gap: 8px; }
.setup-sum .setup-sum-label { color: var(--ink-2); }
.setup-sum .n { color: var(--ink-3); font-weight: 500; }
.setup-sum .chev { margin-left: auto; display: inline-flex; color: var(--ink-3); transition: transform .2s ease; }
.setup-sum .chev svg { width: 16px; height: 16px; }
.setup-sect[open] > .setup-sum .chev { transform: rotate(90deg); }
.setup-sect > summary:hover .setup-sum-label { color: var(--ink); }
.setup-note { color: var(--ink-2); font-size: .875rem; line-height: 1.4; margin: 0 4px 10px; }

/* set-up row: no tick — you set it up, you don't "complete" it */
.task-row.setup { cursor: pointer; }
.task-row.setup:active { background: color-mix(in srgb, var(--ink) 4%, transparent); }
.task-row.setup .task-due.muted { color: var(--ink-3); }
.setup-cue {
  display: inline-flex; align-items: center; gap: 1px; flex: 0 0 auto;
  color: var(--ink-3); font-size: .875rem; font-weight: 600;
}
.setup-cue svg { width: 15px; height: 15px; }

/* set-up sheet actions */
.setup-lead { color: var(--ink-2); font-size: .9375rem; margin: 16px 0; }
.sp-actions { display: flex; flex-direction: column; gap: 10px; }
.sp-actions .btn.big { margin-top: 0; }
.sp-datebox { display: flex; gap: 10px; align-items: center; }
.sp-datebox[hidden] { display: none; }
.sp-datebox .sp-dateinput {
  flex: 1; min-width: 0; background-color: var(--canvas); border: 1px solid var(--line-2); color: var(--ink);
  border-radius: var(--r-md); padding: 12px 14px; font: inherit; font-size: 1.0625rem;
}
.sp-datebox .sp-dateinput:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.sp-datebox .btn { flex: 0 0 auto; }
.sp-remove { margin: 8px auto 0; }

/* overdue urgency — a subtle danger wash under the pill (no side-stripe) */
.task-row.overdue { background: var(--danger-soft); }
.task-row.overdue:active { background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* ---------- segmented control (auth) ---------- */
.seg {
  position: relative; display: flex; gap: 2px; background: var(--surface); border-radius: var(--r-md);
  padding: 3px; margin-bottom: 24px;
}
.seg-btn {
  position: relative; z-index: 1;
  flex: 1; padding: 9px 8px; border: none; background: transparent; color: var(--ink-2);
  font: inherit; font-weight: 600; font-size: .9375rem; border-radius: 11px; cursor: pointer;
  transition: color .2s ease;
}
.seg-btn.on { color: var(--ink); }
.seg-btn:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 1px; }
/* sliding thumb — positioned by JS (enhanceSeg) */
.seg-thumb {
  position: absolute; top: 3px; bottom: 3px; left: 0; width: 0; z-index: 0; pointer-events: none;
  background: var(--bg); border-radius: 11px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 1px rgba(0, 0, 0, .04);
  transition: transform .3s cubic-bezier(.32, .72, 0, 1), width .3s cubic-bezier(.32, .72, 0, 1);
}
@media (prefers-reduced-motion: reduce) { .seg-thumb { transition: none; } }

/* ---------- brand mark ---------- */
.brand-mark {
  width: 60px; height: 60px; border-radius: 16px; margin: 0 auto 18px;
  display: grid; place-items: center; color: #fff; font-weight: 700; font-size: 1.85rem;
  letter-spacing: -0.03em; background: var(--ink);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .14);
}
.brand-mark.big { width: 68px; height: 68px; border-radius: 18px; font-size: 2.1rem; }

/* ---------- centered hero (auth / no-home / onboarding / join) ---------- */
.hero { text-align: center; padding: 22px 0 26px; }
.hero h1 { margin-bottom: 8px; }
.hero .lede { max-width: 34ch; margin: 0 auto; }

/* ---------- choice rows (no-home) ---------- */
.choice { margin: 8px 0 24px; }
.choice-row {
  width: 100%; display: flex; align-items: center; gap: 14px; text-align: left;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 18px 16px; cursor: pointer; color: var(--ink); margin-bottom: 12px;
  transition: border-color .15s ease, transform .1s ease, background .15s ease;
}
.choice-row:hover { border-color: var(--line-2); background: var(--surface); }
.choice-row:active { transform: scale(.99); }
.choice-row .c-body { flex: 1; }
.choice-row h3 { margin-bottom: 3px; }
.choice-row p { color: var(--ink-2); font-size: .9375rem; }
.choice-row .chev { color: var(--ink-3); flex: 0 0 auto; }
.choice-row .chev svg { width: 18px; height: 18px; }

/* ---------- onboarding feature gate (checkable rows) ---------- */
.check {
  display: flex; align-items: center; gap: 14px; cursor: pointer; user-select: none;
  background: var(--bg); border-bottom: 1px solid var(--line); padding: 15px 16px;
  transition: background .12s ease;
}
.check:last-child { border-bottom: none; }
.check:hover { background: var(--surface); }
.check:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: -2px; }
.check .label { flex: 1; font-size: 1.0625rem; }
.check .box {
  flex: 0 0 24px; width: 24px; height: 24px; border-radius: 50%;
  border: 1.8px solid var(--line-2); display: grid; place-items: center;
  color: #fff; transition: background .14s ease, border-color .14s ease;
}
.check .box svg { width: 14px; height: 14px; opacity: 0; transition: opacity .12s ease; }
.check.on .box { background: var(--accent); border-color: var(--accent); }
.check.on .box svg { opacity: 1; }
.check .cat-ico { width: 30px; height: 30px; border-radius: 9px; }
.check .cat-ico svg { width: 17px; height: 17px; }

/* ---------- onboarding: infer → confirm ---------- */
.ob-lead { margin: 4px 0 22px; }
.ob-lead h1 { font-size: 1.9rem; font-weight: 700; letter-spacing: -0.024em; line-height: 1.1; text-wrap: balance; }
.ob-lead .lede { margin-top: 8px; max-width: 40ch; }

/* Subject rename — tap the title to rename a unit or a pet; a stable subtitle (the equipment type,
   or the pet's species) stays shown beneath, so a nickname ("Upstairs AC") never loses its meaning. */
.rename-title { margin-bottom: 6px; }
.rename-btn {
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%;
  background: none; border: none; padding: 2px 0; margin: 0; cursor: text; text-align: left;
  color: inherit; border-radius: 8px;
}
.rename-btn h1 { font-size: 1.9rem; font-weight: 700; letter-spacing: -0.024em; line-height: 1.1; }
.rename-pen { display: inline-flex; flex: 0 0 auto; color: var(--ink-3); opacity: .65; transition: opacity .15s ease, color .15s ease; }
.rename-pen svg { width: 17px; height: 17px; }
.rename-btn:hover .rename-pen, .rename-btn:focus-visible .rename-pen { opacity: 1; color: var(--accent); }
.rename-btn:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }
.rename-sub { margin-top: 2px; color: var(--ink-2); font-size: .9375rem; font-weight: 500; }

.rename-edit { display: flex; align-items: center; gap: 10px; }
.rename-input {
  flex: 1 1 auto; min-width: 0; background: var(--bg); border: 1px solid var(--accent); color: var(--ink);
  border-radius: var(--r-md); padding: 9px 13px; font: inherit; font-size: 1.5rem; font-weight: 700;
  letter-spacing: -0.02em; box-shadow: 0 0 0 4px var(--accent-soft); -webkit-appearance: none; appearance: none;
}
.rename-input:focus { outline: none; }
.rename-edit .rename-save { flex: 0 0 auto; }

/* ---------- reference photos ("how it goes") ---------- */
.photo-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.photo-grid.empty { display: none; }
.photo-tile {
  position: relative; aspect-ratio: 1; border: none; padding: 0; margin: 0; cursor: pointer;
  border-radius: 12px; overflow: hidden; background: var(--canvas); box-shadow: inset 0 0 0 1px var(--line);
}
.photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-tile .photo-cap {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 16px 8px 6px; color: #fff;
  font-size: .75rem; line-height: 1.2; text-align: left; font-weight: 500;
  background: linear-gradient(to top, rgba(0, 0, 0, .62), transparent);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.photo-tile.pending { pointer-events: none; }
.photo-tile.pending img { opacity: .5; }
.photo-spin {
  position: absolute; top: 50%; left: 50%; width: 22px; height: 22px; margin: -11px 0 0 -11px;
  border: 2.5px solid rgba(255, 255, 255, .5); border-top-color: #fff; border-radius: 50%;
  animation: pv-spin .8s linear infinite;
}
@keyframes pv-spin { to { transform: rotate(360deg); } }
.photo-add {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 10px; padding: 13px; border-radius: var(--r-md);
  border: 1px dashed var(--line-2); color: var(--accent); font-weight: 600; font-size: 1rem; cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.photo-grid.empty + .photo-add { margin-top: 0; }
.photo-add:hover, .photo-add:active { background: var(--accent-soft); border-color: var(--accent); }
.photo-add svg { width: 20px; height: 20px; }
.photo-hint { margin-top: 8px; }

/* read-only strip in the task peek */
.photo-strip { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.photo-strip::-webkit-scrollbar { display: none; }
.photo-thumb {
  flex: 0 0 auto; width: 88px; height: 88px; border: none; padding: 0; cursor: pointer;
  border-radius: 12px; overflow: hidden; background: var(--canvas); box-shadow: inset 0 0 0 1px var(--line);
}
.photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* full-screen viewer (lightbox) */
.photo-viewer {
  position: fixed; inset: 0; z-index: 200; display: flex; flex-direction: column;
  background: rgba(8, 12, 10, .96);
  padding: calc(env(safe-area-inset-top) + 8px) 0 calc(var(--safe-bot) + 10px);
  animation: pv-fade .18s ease;
}
@keyframes pv-fade { from { opacity: 0; } }
.pv-close {
  position: absolute; top: calc(env(safe-area-inset-top) + 8px); right: 12px; z-index: 3;
  width: 40px; height: 40px; border: none; border-radius: 50%; background: rgba(255, 255, 255, .14); color: #fff;
  display: grid; place-items: center; cursor: pointer;
}
.pv-close svg { width: 22px; height: 22px; }
/* touch-action:none — the stage owns its gestures (pinch/pan), so the browser mustn't try to
   scroll or (where it's allowed) page-zoom underneath them */
.pv-stage { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; position: relative; padding: 8px; touch-action: none; overflow: hidden; }
.pv-img {
  max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 8px;
  transform-origin: center center; will-change: transform; -webkit-user-select: none; user-select: none;
  -webkit-user-drag: none;
}
/* zoomed: the arrows would fight the pan, and the caption bar competes with the detail you
   zoomed in to read */
.pv-stage.zoomed .pv-nav { opacity: 0; pointer-events: none; }
.pv-nav { transition: opacity .18s ease; }
@media (prefers-reduced-motion: reduce) { .pv-nav { transition: none; } }
.pv-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 44px; height: 44px; border: none; border-radius: 50%; background: rgba(255, 255, 255, .14); color: #fff;
  display: grid; place-items: center; cursor: pointer;
}
.pv-nav.prev { left: 10px; }
.pv-nav.next { right: 10px; }
.pv-nav svg { width: 24px; height: 24px; }
.pv-bar { flex: 0 0 auto; padding: 14px 18px 4px; }
.pv-caption { font-size: 1rem; line-height: 1.35; color: #fff; text-align: center; }
.pv-caption.empty { color: rgba(255, 255, 255, .5); font-style: italic; }
.pv-actions { display: flex; justify-content: center; align-items: center; gap: 22px; margin-top: 12px; }
/* .photo-viewer prefix outranks the global "Delete this task" link (display:block; margin:_ auto),
   whose auto side-margins would otherwise shove the Delete button right + down inside this row. */
.photo-viewer .pv-actions .link { color: #fff; display: inline-flex; align-items: center; gap: 6px; margin: 0; padding: 4px 2px; }
.photo-viewer .pv-actions .link.danger { color: #ff8a80; }
.pv-actions .link svg { width: 16px; height: 16px; }
.pv-cap-edit { display: flex; gap: 8px; align-items: center; max-width: 480px; margin: 0 auto; }
.pv-cap-input {
  flex: 1 1 auto; min-width: 0; background: rgba(255, 255, 255, .12); border: 1px solid rgba(255, 255, 255, .3);
  color: #fff; border-radius: var(--r-md); padding: 10px 12px; font: inherit; font-size: 1rem; -webkit-appearance: none;
}
.pv-cap-input::placeholder { color: rgba(255, 255, 255, .5); }
.pv-cap-input:focus { outline: none; border-color: #fff; }
@media (prefers-reduced-motion: reduce) { .photo-viewer { animation: none; } .photo-spin { animation-duration: 1.6s; } }

.onboard .top .mid { color: var(--ink-3); font-size: .8125rem; font-weight: 600; letter-spacing: .02em; }
.ob-cta { margin-top: 24px; }
.ob-cta .btn { width: 100%; }

/* infer — "what we already know" cards. Tap to keep/drop the inferred task. */
.insight-card {
  display: block; position: relative; width: 100%; text-align: left; cursor: pointer;
  background: var(--bg); border: 1.5px solid var(--line); border-radius: var(--r-md);
  padding: 18px 48px 16px 18px; margin-bottom: 12px; color: var(--ink); font: inherit;
  box-shadow: var(--shadow-card); transition: border-color .15s ease, background .15s ease, transform .1s ease;
}
.insight-card:hover { border-color: var(--line-2); }
.insight-card:active { transform: scale(.99); }
.insight-card:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }
.insight-card.on { border-color: var(--accent); background: linear-gradient(0deg, var(--accent-soft), var(--accent-soft)), var(--bg); }
.insight-card .ic-check {
  position: absolute; top: 16px; right: 16px; width: 26px; height: 26px; border-radius: 50%;
  border: 1.8px solid var(--line-2); display: grid; place-items: center; color: #fff;
  transition: background .14s ease, border-color .14s ease;
}
.insight-card .ic-check svg { width: 15px; height: 15px; opacity: 0; transition: opacity .12s ease; }
.insight-card.on .ic-check { background: var(--accent); border-color: var(--accent); }
.insight-card.on .ic-check svg { opacity: 1; }
.ic-badge {
  display: inline-block; margin-bottom: 8px; background: var(--warn-soft); color: var(--warn);
  font-size: .6875rem; font-weight: 700; letter-spacing: .01em; text-transform: uppercase;
  padding: 3px 9px; border-radius: var(--r-pill);
}
.ic-head { font-size: 1.1875rem; font-weight: 650; letter-spacing: -0.016em; line-height: 1.2; text-wrap: balance; }
/* Card text sits on the selected pine tint, where the standard --ink-2/--ink-3 ramp drops below
   4.5:1. These darker secondaries hold AA on the tint (6.5:1 / 5.3:1) while staying clearly secondary. */
.ic-detail { color: #525258; font-size: .9375rem; line-height: 1.45; margin-top: 6px; text-wrap: pretty; }
.ic-task { font-size: .875rem; color: #525258; margin-top: 12px; }
.ic-task b { color: var(--ink); font-weight: 600; }
.ic-src { color: #5f5f66; font-size: .75rem; line-height: 1.4; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }

/* confirm — equipment inventory. Grouped subheads + tap-to-select cards. */
/* Section labels match the app's form-label convention (sentence case, no tracking) — a tracked
   uppercase label repeated over every category would read as scaffolding, not hierarchy. */
.equip-group {
  font-size: .8125rem; font-weight: 600; letter-spacing: 0;
  color: var(--ink-2); margin: 24px 4px 10px;
}
.equip-group:first-child { margin-top: 6px; }
.equip-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.equip-card {
  position: relative; display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  background: var(--bg); border: 1.5px solid var(--line); border-radius: var(--r-md);
  padding: 15px 14px; cursor: pointer; font: inherit; color: var(--ink);
  box-shadow: var(--shadow-card); transition: border-color .15s ease, background .15s ease, transform .1s ease;
}
.equip-card:hover { border-color: var(--line-2); }
.equip-card:active { transform: scale(.97); }
.equip-card:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }
.equip-card.on { border-color: var(--accent); background: linear-gradient(0deg, var(--accent-soft), var(--accent-soft)), var(--bg); }
.equip-card .cat-ico { width: 34px; height: 34px; border-radius: 10px; }
.equip-card .cat-ico svg { width: 19px; height: 19px; }
.ec-label { font-size: .9375rem; font-weight: 550; letter-spacing: -0.01em; line-height: 1.25; }
.equip-card .ec-check {
  position: absolute; top: 12px; right: 12px; width: 22px; height: 22px; border-radius: 50%;
  border: 1.8px solid var(--line-2); display: grid; place-items: center; color: #fff;
  opacity: 0; transform: scale(.8); transition: opacity .14s ease, transform .14s ease, background .14s ease, border-color .14s ease;
}
.equip-card .ec-check svg { width: 13px; height: 13px; }
.equip-card.on .ec-check { opacity: 1; transform: scale(1); background: var(--accent); border-color: var(--accent); }
.equip-card.owned { opacity: .5; cursor: default; }
.equip-card.owned .ec-check { opacity: 1; transform: scale(1); background: var(--accent); border-color: var(--accent); }
.ec-owned-note { font-size: .75rem; color: var(--ink-2); margin-top: -4px; }

/* quantity stepper for multiple-capable equipment (e.g. two A/C units) —
   always visible so the tile reads as a counter, not a checkbox */
.ec-qty {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  align-self: stretch; margin-top: 2px; padding: 4px;
  background: var(--canvas); border: 1px solid var(--line); border-radius: 999px;
}
.equip-card.on .ec-qty { background: var(--bg); border-color: transparent; }
.qty-btn {
  width: 28px; height: 28px; flex: 0 0 auto; border: none; border-radius: 50%;
  background: var(--bg); color: var(--ink); display: grid; place-items: center;
  cursor: pointer; box-shadow: var(--shadow-card); transition: transform .1s ease, background .15s ease, opacity .15s ease;
}
.equip-card.on .qty-btn { background: var(--surface); }
.qty-btn:active { transform: scale(.9); }
.qty-btn svg { width: 15px; height: 15px; }
/* nothing to remove yet — dim the minus until there's at least one */
.equip-card:not(.on) .qdec { opacity: .35; pointer-events: none; }
.qty-n { min-width: 16px; text-align: center; font-weight: 650; font-size: 1rem; font-variant-numeric: tabular-nums; }
.equip-card:not(.on) .qty-n { color: var(--ink-3); }

/* pinned commit bar: keep "Add" in view so picks don't feel lost below the grid */
.inventory .ob-cta {
  position: sticky; bottom: calc(70px + var(--safe-bot)); z-index: 5;
  margin: 20px -20px 0; padding: 14px 20px;
  background: var(--canvas); border-top: 1px solid var(--line);
}

/* ---------- bottom tab bar ----------
   A centered floating pill at every size (not a full-width strip) — the more modern treatment, and
   it keeps the bar clear of the screen edges so content reads to the corners. */
body.has-tabbar .screen { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }
.tabbar {
  position: fixed; left: 50%; right: auto; bottom: 0; z-index: 30;
  width: min(440px, calc(100% - 28px));
  display: flex; gap: 4px; padding: 8px 12px;
  margin-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  /* Solid (not glass): position:fixed + backdrop-filter is an iOS Safari bug where the bar
     scrolls with the page instead of staying pinned. An opaque surface stays rock-solid. */
  background: var(--bg);
  border: 1px solid var(--line); border-radius: 22px; box-shadow: var(--shadow-raise);
  transform: translate(-50%, 160%); transition: transform .28s cubic-bezier(.22, 1, .36, 1);
}
.tabbar.show { transform: translate(-50%, 0); }
.tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: none; border: none; cursor: pointer; padding: 7px 4px 5px; border-radius: 12px;
  color: var(--ink-3); font: inherit; transition: color .15s ease;
}
.tab:active { background: var(--surface); }
.tab-ico { display: inline-flex; }
.tab-ico svg { width: 24px; height: 24px; }
.tab-label { font-size: .6875rem; font-weight: 600; letter-spacing: -0.004em; }
.tab.on { color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .tabbar { transition: none; } }

/* ---------- manage (hub + drivers) ---------- */
.mng-head { padding: 6px 0 16px; }
.mng-h1 { font-size: 1.9rem; font-weight: 700; letter-spacing: -0.024em; line-height: 1.1; }
.mng-head .lede { margin-top: 6px; max-width: 40ch; }
.mng-row { padding: 16px; }
.mng-row .cat-ico.lg { background: color-mix(in srgb, currentColor 15%, transparent); }
.mng-row .st-body strong { font-size: 1.0625rem; font-weight: 650; letter-spacing: -0.01em; }
.mng-row .st-body .fine { margin-top: 2px; }
.mng-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 24px 4px 10px; }
.mng-sec-head .btn.small { padding: 6px 12px; }
.insight-card.static { cursor: default; padding-right: 18px; }
.insight-card.static:hover { border-color: var(--line); }
.ic-action { margin-top: 14px; }
.added-pill { display: inline-flex; align-items: center; gap: 5px; color: var(--accent-press); font-size: .8125rem; font-weight: 650; }
.added-pill svg { width: 15px; height: 15px; }
/* manage rows — toggle + expandable recurrence editor / detail (pets, appliances, home, business) */
.care-list { background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card); overflow: hidden; }
.care-item + .care-item { border-top: 1px solid var(--line); }
/* grouped pet care — a labeled section per group (Grooming, Dental, …) */
.pet-care-group + .pet-care-group { margin-top: 20px; }
.pet-care-group .form-label { margin: 0 4px 8px; }

/* multi-pet parity bar (compare / match / link) + the per-activity "differs" note */
.pet-parity { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card); padding: 13px 15px; margin-bottom: 16px; }
.pet-parity .pp-ico { color: var(--accent); display: inline-flex; flex: 0 0 auto; }
.pet-parity .pp-ico svg { width: 20px; height: 20px; }
.pet-parity .pp-text { flex: 1; min-width: 180px; display: flex; flex-direction: column; gap: 2px; }
.pet-parity .pp-text strong { font-size: 1rem; font-weight: 640; letter-spacing: -0.01em; }
.pet-parity .pp-sub { font-size: .8125rem; color: var(--ink-2); line-height: 1.35; }
.pet-parity .pp-actions { display: flex; gap: 8px; flex: 0 0 auto; margin-left: auto; }
.pet-parity.linked { background: var(--accent-soft); }
.co-subhint { display: block; font-size: .75rem; font-weight: 600; color: var(--warn); margin-top: 2px; letter-spacing: -0.005em; }

/* Pets list "Compare their care" button */
.pets-compare-btn { display: inline-flex; align-items: center; gap: 7px; margin: 12px 0 4px; }
.pets-compare-btn svg { width: 16px; height: 16px; }

/* Compare grid — activities × pets, tap a cell to fix a gap.
   The card keeps a real gutter on BOTH edges (--cmp-gut): the label column pads in from the
   left, the last pet column pads in from the right. Columns carry min-widths so a cadence is
   never crushed — past ~3 pets the card scrolls sideways (with a fade hint) instead of
   letting names collide and clipping the last column at the card edge. */
.cmp-seg { margin: 2px 0 18px; }
.cmp-sec { --cmp-gut: 16px; margin-bottom: 24px; }
.cmp-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 2px 10px; }
.cmp-sec-head > .form-label { margin: 0; }
.cmp-sec-head .btn.small { padding: 6px 12px; flex: 0 0 auto; }
/* the fade sits over the card's right edge while there's more to scroll to */
.cmp-scroll { position: relative; }
.cmp-scroll::after {
  content: ''; position: absolute; top: 1px; right: 0; bottom: 1px; width: 34px; border-radius: 0 16px 16px 0;
  background: linear-gradient(to right, rgba(255, 255, 255, 0), var(--bg) 72%);
  opacity: 0; transition: opacity .18s ease; pointer-events: none;
}
.cmp-scroll.more::after { opacity: 1; }
.cmp-wrap { overflow-x: auto; border-radius: 16px; box-shadow: var(--shadow-card); background: var(--bg); -webkit-overflow-scrolling: touch; }
.cmp-grid { border-collapse: collapse; width: 100%; }
/* No blanket `.cmp-grid th, td { padding: 0 }` here: at (0,1,1) it out-specifies every
   single-class cell rule below and silently zeroes their padding. The global `*` reset
   (top of file) already clears the UA default, so each cell just states its own. */
.cmp-corner { position: sticky; left: 0; z-index: 3; background: var(--bg); min-width: 140px; }
.cmp-pet { padding: 13px 5px 11px; text-align: center; vertical-align: bottom; border-bottom: 1px solid var(--line); min-width: 62px; background: var(--bg); }
.cmp-pet:last-child { padding-right: var(--cmp-gut); }
/* wrap at spaces only — a name is never broken mid-word ("Coope/r"). An unbreakable name
   widens its column instead, and the card scrolls if that pushes it past the edge. */
.cmp-pet-name { display: block; font-weight: 650; font-size: .9375rem; line-height: 1.25; letter-spacing: -0.01em; }
.cmp-grouprow td { position: sticky; left: 0; padding: 14px var(--cmp-gut) 6px; font-size: .6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3); background: var(--bg); }
.cmp-row + .cmp-row .cmp-act, .cmp-row + .cmp-row .cmp-cell { border-top: 1px solid var(--line); }
/* min/max widths are border-box, so they include the gutter — content gets ~104-136px */
.cmp-act { position: sticky; left: 0; z-index: 1; text-align: left; padding: 11px 12px 11px var(--cmp-gut); font-size: .9375rem; font-weight: 550; line-height: 1.3; letter-spacing: -0.01em; color: var(--ink); min-width: 140px; max-width: 176px; background: var(--bg); }
.cmp-row.differs .cmp-act, .cmp-row.differs .cmp-cell { background: var(--warn-soft); }
.cmp-cell { text-align: center; padding: 5px 3px; border-left: 1px solid var(--line); background: var(--bg); min-width: 62px; }
.cmp-cell:last-child { padding-right: var(--cmp-gut); }
.cmp-dot { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px; width: 100%; min-width: 40px; min-height: 40px; padding: 5px 3px; border: none; border-radius: 11px; background: transparent; color: var(--ink-3); cursor: pointer; font: inherit; transition: background .12s ease; }
.cmp-dot.on { color: var(--accent); }
.cmp-dot svg { width: 17px; height: 17px; }
.cmp-dot.off svg { opacity: .45; }
.cmp-dot:active { background: var(--surface); }
.cmp-cad { font-size: .6875rem; font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.cmp-allmatch { display: flex; align-items: center; gap: 9px; padding: 16px; background: var(--ok-soft); border-radius: 14px; color: color-mix(in srgb, var(--ok) 86%, var(--ink)); font-size: .9375rem; font-weight: 560; }
.cmp-allmatch svg { width: 20px; height: 20px; color: var(--ok); flex: 0 0 auto; }

/* "Match care" summary sheet — every add, cadence change, and removal named before it runs.
   Copying a plan deletes tasks (and their history), so the sheet IS the confirmation. */
/* the sheet is height-capped, so the op list scrolls and the actions stay reachable */
.ms { display: flex; flex-direction: column; min-height: 0; }
.ms-h { font-size: 1.25rem; font-weight: 680; letter-spacing: -0.02em; margin: 2px 0 4px; flex: 0 0 auto; }
.ms-lede { color: var(--ink-2); font-size: .9375rem; line-height: 1.4; margin-bottom: 14px; text-wrap: pretty; flex: 0 0 auto; }
.ms-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; margin: 0 -4px; padding: 0 4px; }
.ms-pet + .ms-pet { margin-top: 16px; }
.ms-pet-name { font-size: .8125rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3); margin-bottom: 7px; }
.ms-ops { list-style: none; display: flex; flex-direction: column; gap: 1px; }
.ms-op { display: flex; align-items: flex-start; gap: 9px; padding: 9px 11px; background: var(--surface); font-size: .9375rem; line-height: 1.35; }
.ms-op:first-child { border-radius: 11px 11px 0 0; }
.ms-op:last-child { border-radius: 0 0 11px 11px; }
.ms-op:only-child { border-radius: 11px; }
.ms-tag { flex: 0 0 auto; font-size: .6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; padding: 2px 7px; border-radius: 999px; margin-top: 1px; }
.ms-op.add .ms-tag { background: var(--ok-soft); color: var(--ok); }
.ms-op.chg .ms-tag { background: var(--accent-soft); color: var(--accent-press); }
.ms-op.rem { background: var(--danger-soft); }
.ms-op.rem .ms-tag { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.ms-op-name { min-width: 0; }
.ms-cad { display: block; color: var(--ink-2); font-size: .8125rem; margin-top: 1px; font-variant-numeric: tabular-nums; }
.ms-note { display: flex; gap: 8px; align-items: flex-start; margin-top: 14px; color: var(--danger); font-size: .8125rem; line-height: 1.4; flex: 0 0 auto; }
.ms-note svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 1px; }
.ms-actions { display: flex; gap: 10px; margin-top: 18px; flex: 0 0 auto; }
.ms-actions .btn { flex: 1; padding: 14px; font-size: 1.0625rem; }
.ms-actions .btn.danger { background: var(--danger); color: #fff; border-color: transparent; }
.ms-actions .btn.danger:hover { background: #b8000f; }
.care-main { display: flex; align-items: center; gap: 12px; padding: 12px 14px; }
.care-main .cat-ico.lg { background: color-mix(in srgb, currentColor 15%, transparent); }
.care-open { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; background: none; border: none; font: inherit; color: inherit; cursor: pointer; padding: 0; text-align: left; -webkit-tap-highlight-color: transparent; }
.care-open:disabled { cursor: default; }
.care-open:focus { outline: none; }
.care-open:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 3px; border-radius: 8px; }
.co-body { flex: 1; min-width: 0; }
.care-open .part-name { display: block; font-weight: 600; font-size: 1.0625rem; letter-spacing: -0.01em; }
.care-open .part-spec { display: block; color: var(--ink-2); font-size: .8125rem; margin-top: 2px; font-variant-numeric: tabular-nums; }
.co-hint { display: block; color: var(--ink-2); font-size: .8125rem; line-height: 1.35; margin-top: 4px; text-wrap: pretty; }
.co-chev { color: var(--ink-3); flex: 0 0 auto; transition: transform .2s ease; }
.co-chev svg { width: 18px; height: 18px; display: block; }
.care-item.open .co-chev { transform: rotate(180deg); }
.care-item.off .cat-ico, .care-item.off .care-open { opacity: .45; }
/* expand panel — smooth height via grid-rows (0fr → 1fr), content aligned under the task name */
.care-edit { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .26s cubic-bezier(.22, 1, .36, 1); }
.care-item.open .care-edit { grid-template-rows: 1fr; }
.care-edit-clip { overflow: hidden; min-height: 0; }
.care-edit-in { padding: 2px 14px 14px 62px; }
.care-detail { color: #525258; font-size: .9375rem; line-height: 1.45; text-wrap: pretty; }
.recur-inline + .care-detail { margin-top: 12px; }
.care-src { color: #5f5f66; font-size: .75rem; line-height: 1.4; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
/* wallet account detail — read-only summary card; editing happens in the "Edit details" form */
.acct-card { background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card); overflow: hidden; }
.acct-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; }
.acct-row + .acct-row, .acct-row + .acct-pay { border-top: 1px solid var(--line); }
.acct-k { color: var(--ink-2); font-size: .9375rem; }
.acct-v { font-weight: 600; font-size: 1.0625rem; font-variant-numeric: tabular-nums; text-align: right; }
.acct-pay { padding: 14px 16px; }
.acct-pay .btn.action.big { width: 100%; }

/* Wallet's add panel — opened by the "+ Add" in the section header, so it sits above the list
   instead of under it. Framed like the form it is, not like another account row. */
.acct-add { background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card); padding: 4px 14px 14px; margin-bottom: 16px; }
.acct-add[hidden] { display: none; }
.acct-add .part-form { background: none; padding: 0; }
/* explicit about beating `.part-form .btn { width: 100%; margin-bottom: 16px }`, which lives
   further down the file and would otherwise stack these two full-width */
.acct-add-actions { display: flex; gap: 10px; margin-top: 4px; }
.acct-add .acct-add-actions .btn { flex: 1 1 0; width: auto; margin-bottom: 14px; }

/* --- occasional-use cards: quiet until you say you used them --- */
.acct-v.is-quiet { color: var(--ink-2); font-weight: 550; }
.acct-v.is-armed { color: var(--warn); }
.acct-v.soft { color: var(--ink-2); font-weight: 500; font-size: .9375rem; text-align: right; }
/* The account form is open on the screen, not hidden behind a "+ Edit details" disclosure —
   a plus reads as "add something", and editing is the reason you opened the card. */
.acct-form-h { margin: 22px 2px 10px; }
/* an on/off inside a form group: a plain row, not a Settings card dropped into a form panel */
.form-switch { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 6px 2px 2px; }
.form-switch > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.form-switch strong { font-size: .9375rem; font-weight: 600; letter-spacing: -0.01em; }
.form-switch em { font-style: normal; font-size: .8125rem; color: var(--ink-2); line-height: 1.35; text-wrap: pretty; }
.mode-note { margin: 2px 2px 14px; line-height: 1.4; text-wrap: pretty; }
.mode-note[hidden] { display: none; }
#onUseFields, #recurFields { display: contents; }
#onUseFields[hidden], #recurFields[hidden] { display: none; }

/* the Wallet row + its one-tap "I used it", paired so the button isn't nested in the row */
.acct-pair { display: flex; flex-direction: column; gap: 0; }
.acct-pair > .nav-row { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
/* .btn.used-btn, not .used-btn: `.btn.ghost` is (0,2,0) and would otherwise win the background */
.btn.used-btn {
  display: flex; align-items: center; justify-content: center; gap: 7px; width: 100%;
  border-radius: 0 0 var(--r-md, 16px) var(--r-md, 16px); border: none; border-top: 1px solid var(--line);
  background: var(--bg); color: var(--accent); font-weight: 600;
}
.btn.used-btn:hover { background: var(--accent-soft); }
.used-btn svg { width: 16px; height: 16px; }

/* the "did you use it?" check-in — a question on the dashboard, never a due task */
.checkin {
  background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card);
  padding: 14px 15px 12px; margin-bottom: 14px; border-left: 3px solid var(--accent-soft);
}
.ci-main { display: flex; align-items: flex-start; gap: 12px; }
.ci-ico { flex: 0 0 auto; display: inline-flex; }
.ci-ico svg { width: 22px; height: 22px; }
.ci-body strong { display: block; font-size: 1.0625rem; font-weight: 650; letter-spacing: -0.01em; }
.ci-body .fine { margin-top: 2px; text-wrap: pretty; }
.ci-actions { display: flex; gap: 8px; margin-top: 12px; }
.ci-actions .btn { flex: 1; }

/* "you used it" sheet — the worked-out due date, and the cycle question when it's too close to call */
.used-sheet .field { margin-top: 4px; }
.cyc-q { font-size: .875rem; color: var(--ink-2); line-height: 1.4; margin: 2px 0 8px; text-wrap: pretty; }
.cyc-opts { display: flex; flex-direction: column; gap: 8px; }
.cyc-opts:empty { display: none; }
.cyc-opt {
  display: flex; flex-direction: column; gap: 2px; text-align: left; width: 100%;
  padding: 12px 14px; border-radius: 13px; border: 1.5px solid var(--line-2);
  background: var(--bg); font: inherit; color: var(--ink); cursor: pointer;
}
.cyc-opt strong { font-weight: 650; font-size: 1rem; }
.cyc-opt span { color: var(--ink-2); font-size: .8125rem; }
.cyc-opt.on { border-color: var(--accent); background: var(--accent-soft); }
.cyc-opt.on strong { color: var(--accent-press); }
.cyc-hint { font-size: .8125rem; color: var(--ink-2); line-height: 1.45; margin-top: 10px; text-wrap: pretty; }
.cyc-hint .link { font-size: .8125rem; padding: 0; vertical-align: baseline; }

/* supplies subsection — full-width within the expand, separated from the schedule editor above */
.care-parts { border-top: 1px solid var(--line); padding: 12px 14px 14px; }
.care-parts-h { font-size: .8125rem; font-weight: 650; color: var(--ink-2); margin: 2px 2px 8px; }
.care-parts .parts-wrap > .list { border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
.care-parts .part-add { margin-top: 10px; }

/* toggle switch */
.switch { position: relative; flex: 0 0 auto; width: 46px; height: 28px; border-radius: 999px; background: var(--surface-press); border: none; cursor: pointer; padding: 0; transition: background .18s ease; }
.switch .knob { position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .22); transition: transform .18s cubic-bezier(.22, 1, .36, 1); }
.switch.on { background: var(--accent); }
.switch.on .knob { transform: translateX(18px); }
.switch:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .switch .knob, .co-chev, .care-edit { transition: none; } }

/* recurrence editor — a balanced "Every [n] [unit]" control */
.recur-inline { display: flex; align-items: center; gap: 10px; }
.recur-inline .recur-prefix { color: var(--ink-2); font-size: .9375rem; flex: 0 0 auto; }
.recur-inline .select-btn { flex: 1; }
/* the count field carries the same pill vocabulary as the selector (was an unstyled raw input).
   scoped to .recur-inline so it beats .field input's width:100% inside the add-care form */
.recur-inline .recur-n {
  flex: 0 0 auto; width: 58px; text-align: center;
  background: var(--bg); border: 1px solid var(--line-2); color: var(--ink);
  border-radius: var(--r-sm); padding: 10px 8px; font: inherit; font-size: 1.0625rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
  -webkit-appearance: none; appearance: none; -moz-appearance: textfield;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.recur-n::-webkit-outer-spin-button, .recur-n::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.recur-inline .recur-n:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* in the expand panel the control is a compact, self-contained group framed on a recessed well,
   so the unit selector sizes to its content instead of stretching the full row width */
.care-edit-in .recur-inline {
  display: inline-flex; gap: 10px; align-items: center;
  background: var(--canvas); border-radius: var(--r-md); padding: 8px 12px 8px 14px;
}
.care-edit-in .recur-inline .recur-prefix { font-weight: 500; }
.care-edit-in .recur-inline .select-btn {
  flex: 0 0 auto; width: auto; padding: 10px 12px; font-size: 1.0625rem; border-radius: var(--r-sm);
}

/* schedule anchor — set "last done" or "due next" while setting a task up in Manage */
.care-anchor { margin-top: 16px; }
.care-anchor-h { display: block; font-size: .8125rem; font-weight: 600; color: var(--ink-2); margin-bottom: 8px; }
.anchor-modes { display: inline-flex; gap: 4px; background: var(--canvas); border-radius: var(--r-md); padding: 4px; margin-bottom: 10px; }
.anchor-pill {
  border: none; background: none; cursor: pointer; font: inherit; font-size: .9375rem; font-weight: 600;
  color: var(--ink-2); padding: 8px 15px; border-radius: var(--r-sm); transition: background .15s ease, color .15s ease;
}
.anchor-pill.on { background: var(--bg); color: var(--accent); box-shadow: var(--shadow-card); }
.care-anchor .anchor-date {
  display: block; background-color: var(--bg); border: 1px solid var(--line-2); color: var(--ink);
  border-radius: var(--r-sm); padding: 10px 12px; font: inherit; font-size: 1.0625rem;
  -webkit-appearance: none; appearance: none;
}
.care-anchor .anchor-date:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* "on the [1st]" / "on [Monday]" / "on [March] [15]" day-of-period picker */
.dop-row { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; background: var(--canvas); border-radius: var(--r-md); padding: 8px 12px; }
.dop-prefix { color: var(--ink-2); font-size: 1rem; font-weight: 500; flex: 0 0 auto; }
.dop-row .select-btn { flex: 0 0 auto; width: auto; padding: 10px 12px; font-size: 1.0625rem; border-radius: var(--r-sm); }

/* join code */
.code-input { text-align: center; text-transform: uppercase; letter-spacing: .24em; font-weight: 700; font-size: 1.25rem; }

/* ---------- detail ---------- */
.detail h1 { margin: 6px 0 8px; }
.detail-due { font-size: 1.0625rem; font-weight: 600; margin-bottom: 16px; }
.detail-due.overdue { color: var(--danger); }
.detail-due.soon { color: var(--warn); }
.detail-due.later { color: var(--ink-2); }
.detail-note { color: var(--ink-2); font-size: 1.0625rem; margin-bottom: 22px; max-width: 68ch; }
.detail-cat { display: inline-flex; align-items: center; gap: 7px; font-size: .9375rem; font-weight: 600; color: var(--ink-2); }
.detail-cat .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--ink-3); }
.interval-line { text-align: center; color: var(--ink-2); font-size: .875rem; margin-top: 14px; }

.sect { margin-top: 32px; }
.sect.first { margin-top: 22px; }
.sect > h3 { margin-bottom: 12px; font-size: .8125rem; font-weight: 600; color: var(--ink-2); padding: 0 4px; }
.protype { color: var(--ink-2); font-size: .9375rem; line-height: 1.4; padding: 0; }
.protype strong { color: var(--ink); font-weight: 600; }

/* assign select (in a framed row) */
.assign-select { background-color: var(--bg); }

/* history */
.hist { list-style: none; }
.hist-row { display: flex; flex-direction: column; gap: 8px; }
.hist-line { display: flex; justify-content: space-between; gap: 12px; }
.hist-row .who { color: var(--ink-2); font-size: .9375rem; }
.hist-row .date { font-size: .9375rem; }

/* completion success step (shown in the task peek after Mark done) */
.done-state { text-align: center; padding: 8px 4px 4px; }
.done-check {
  width: 60px; height: 60px; margin: 8px auto 14px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent); display: grid; place-items: center;
}
.done-check svg { width: 32px; height: 32px; }
.done-title { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; }
.done-sub { color: var(--ink-2); margin: 6px 0 18px; }
.done-photos:not(:empty) { margin-bottom: 14px; }
.done-photos .photo-strip { justify-content: center; }
.done-add { margin-top: 0; margin-bottom: 12px; }
.done-state .done-close { width: 100%; }

/* ---------- parts ---------- */
.part .part-info { flex: 1; min-width: 0; }
/* edit-screen part row: the info is a tap target that opens the full editor */
.part button.part-info { background: none; border: none; text-align: left; font: inherit; color: inherit; cursor: pointer; padding: 0; display: block; }
.part-name { font-weight: 600; font-size: 1.0625rem; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.part-spec { color: var(--ink-2); font-size: .875rem; margin-top: 2px; }
.part-stock { color: var(--ink-2); font-size: .875rem; margin-top: 3px; }
.part-stock strong { color: var(--ink); }
.part-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; flex: 0 0 auto; }

/* quiet on-hand stepper (edit screen) — adjust stock up or down, no prominent pill */
.stepper { display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto; background: var(--surface); border-radius: 11px; padding: 2px; }
.step-btn {
  width: 34px; height: 32px; display: grid; place-items: center;
  background: none; border: none; border-radius: 9px; color: var(--ink); cursor: pointer;
  transition: background .15s ease, transform .1s ease;
}
.step-btn svg { width: 18px; height: 18px; }
.step-btn:hover { background: var(--surface-press); }
.step-btn:active { transform: scale(.9); }
.step-btn[disabled] { color: var(--ink-3); opacity: .45; cursor: default; }
.step-btn.pending { color: var(--ink-3); opacity: .4; } /* decrement held until backend supports it */
.step-n { min-width: 26px; text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }
.part-del {
  background: none; border: none; color: var(--ink-3); cursor: pointer;
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  transition: color .15s ease, background .15s ease;
}
.part-del svg { width: 16px; height: 16px; }
.part-del:hover { color: var(--danger); background: var(--danger-soft); }
.affiliate-note { color: var(--ink-3); font-size: .78rem; margin: 10px 4px 0; }

/* ---------- life-manager: profile + guided setup ---------- */
.nav-row {
  width: 100%; display: flex; align-items: center; gap: 12px; text-align: left; cursor: pointer;
  background: var(--bg); border: none; font: inherit; color: inherit;
  padding: 15px 16px; border-radius: 16px; box-shadow: var(--shadow-card);
  transition: background .15s ease;
}
.nav-row:hover { background: var(--surface); }
.nav-row .st-body { flex: 1; min-width: 0; }
.nav-chev { color: var(--ink-3); display: inline-flex; flex: 0 0 auto; }
.nav-chev svg { width: 18px; height: 18px; }

.veh-row { gap: 12px; }
.veh-row .cat-ico.lg { background: color-mix(in srgb, currentColor 15%, transparent); }

.guide-h1 { font-size: 1.75rem; font-weight: 700; letter-spacing: -0.022em; line-height: 1.12; text-wrap: balance; }
.guide-tiles { display: grid; gap: 12px; }
.guide-tiles.cols2 { grid-template-columns: 1fr 1fr; }
.guide-tiles.cols2 .guide-tile { padding: 18px 16px; }
.guide-tiles.cols2 .guide-tile span { font-size: .875rem; }
.guide-tile.other { box-shadow: none; border: 1.5px dashed var(--line-2); background: transparent; }
.guide-tile.other:hover { background: var(--bg); }
.guide-tile.other .cat-ico.lead { background: var(--surface); }
.guide-tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; text-align: left;
  background: var(--bg); border: none; box-shadow: var(--shadow-card); border-radius: var(--r-md);
  padding: 20px; cursor: pointer; font: inherit; color: var(--ink);
  transition: transform .1s ease;
}
.guide-tile:active { transform: scale(.98); }
.guide-tile .cat-ico.lead { margin-bottom: 10px; }
.guide-tile b { font-size: 1.1875rem; font-weight: 650; letter-spacing: -0.018em; }
.guide-tile span { color: var(--ink-2); font-size: .9375rem; }

.opt-head { display: flex; align-items: center; gap: 12px; }
.opt-head .cat-ico.lead { width: 44px; height: 44px; }
.opt-head .guide-h1 { margin: 0; }

/* clean pick-list: name + an optional "we know the date" tag + chevron. No redundant per-row icon
   (they'd all repeat the category) and no truncated descriptions (those live on the next screen). */
.opt-row { width: 100%; text-align: left; cursor: pointer; gap: 10px; align-items: center; padding: 17px 16px; border: none; border-bottom: 1px solid var(--line); }
.opt-row:last-child { border-bottom: none; }
.opt-row:hover { background: var(--surface); }
.opt-row:active { background: var(--surface-press); }
.opt-row:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.opt-name { flex: 1; min-width: 0; font-size: 1.0625rem; font-weight: 550; letter-spacing: -0.012em; line-height: 1.25; text-wrap: balance; }
.opt-tag { flex: 0 0 auto; background: var(--accent-soft); color: var(--accent-press); font-size: .75rem; font-weight: 700; letter-spacing: -0.005em; padding: 3px 9px; border-radius: var(--r-pill); white-space: nowrap; }
.badge.prefill {
  background: var(--accent-soft); color: var(--accent-press);
  font-size: .6875rem; font-weight: 700; padding: 2px 7px; border-radius: var(--r-pill);
  margin-left: 8px; vertical-align: middle;
}
.guide-confirm { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.guide-confirm .k { color: var(--ink-2); font-size: .9375rem; }
.guide-confirm .v { font-size: 1.1875rem; font-weight: 650; letter-spacing: -0.01em; }
.guide-dates { display: flex; flex-wrap: wrap; gap: 8px; }
.date-pill { background: var(--surface); color: var(--ink); font-weight: 600; font-size: .9375rem; padding: 8px 14px; border-radius: var(--r-pill); }
.term-wrap { display: flex; align-items: center; gap: 12px; margin-top: 14px; flex-wrap: wrap; }
.term-wrap .term-seg { flex: 1 1 auto; min-width: 180px; }
.disclaimer { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); color: var(--ink-3); font-size: .8125rem; line-height: 1.45; }

/* add-part disclosure */
.part-add { margin-top: 12px; }
.part-add > summary {
  cursor: pointer; color: var(--accent); font-weight: 600; font-size: 1rem;
  padding: 8px 4px; list-style: none; display: inline-flex; align-items: center; gap: 6px;
}
.part-add > summary::-webkit-details-marker { display: none; }
.part-add > summary svg { width: 16px; height: 16px; }
.part-form {
  background: var(--surface); border-radius: var(--r-md); padding: 16px 15px 4px; margin-top: 8px;
}
.part-form .field input, .part-form .field select { background-color: var(--bg); }
/* Paired number fields: "Rebuy at — 0 = never remind me" wraps to two lines next to the shorter
   "Used each time", so let each cell stretch and pin its input to the bottom — same fix as the
   appliance details grid. Below 420px they stack, since two ~150px columns clip their own content. */
.part-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.part-pair .field { display: flex; flex-direction: column; }
.part-pair .field > input { margin-top: auto; }
@media (max-width: 420px) { .part-pair { grid-template-columns: 1fr; } }
.part-form .btn { width: 100%; margin-bottom: 16px; }

/* ---------- badges ---------- */
.badge {
  font-size: .6875rem; font-weight: 700; letter-spacing: .01em;
  padding: 3px 9px; border-radius: var(--r-pill); line-height: 1.4; white-space: nowrap;
}
.badge.low { background: var(--warn-soft); color: var(--warn); }
.badge.you { background: var(--surface); color: var(--ink-2); }
.badge.role { background: var(--surface); color: var(--ink-2); text-transform: capitalize; }
.badge.role.owner { background: var(--accent-soft); color: var(--accent-press); }

/* ---------- settings ---------- */
.home-line { font-size: 1.0625rem; font-weight: 600; padding: 0 2px 4px; }
.home-name-row { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.home-name-row .home-line { flex: 1; min-width: 0; padding: 0 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-name-row.editing { align-items: stretch; flex-direction: column; gap: 10px; }
/* the home name is the first row of the Home card (not floating above it) */
.list .home-name-row { margin: 0; }
.list .home-name-row .home-line { padding: 0; font-weight: 650; letter-spacing: -0.01em; }
.rename-input {
  width: 100%; background: var(--bg); border: 1px solid var(--line-2); color: var(--ink);
  font: inherit; font-size: 1.0625rem; font-weight: 600; padding: 12px 14px; border-radius: var(--r-sm);
}
.rename-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.rename-actions { display: flex; justify-content: flex-end; gap: 8px; }
.nav-stack { display: flex; flex-direction: column; gap: 10px; }
/* Manage hubs (Manage + Home) — few nav cards of varied text; a single centered column reads far
   cleaner than a ragged 2-col grid. Titles/subs stay one line so every card is the same height. */
.mng-hub { max-width: 600px; }
.mng-hub .st-body strong { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mng-hub .st-body .fine { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.invite-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.invite-main { min-width: 0; }
.invite-row .code { font-size: 1.2rem; font-weight: 700; letter-spacing: .14em; margin-top: 2px; }
.invite-actions { display: flex; gap: 8px; flex: 0 0 auto; }

.setting-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.setting-row .st-body strong { font-weight: 600; }
.setting-row .st-body .fine { margin-top: 3px; }
.setting-na { color: var(--ink-3); font-size: .9375rem; flex: 0 0 auto; }

.member-info { flex: 1; min-width: 0; }
.member-name { font-weight: 600; display: flex; align-items: center; gap: 8px; }
.member-email { color: var(--ink-2); font-size: .875rem; margin-top: 1px; }

.home-switch-row { width: 100%; text-align: left; background: var(--bg); border: none; font: inherit; color: var(--ink); cursor: pointer; }
.home-switch-row + .home-switch-row { border-top: 1px solid var(--line); }
.home-switch-row:hover { background: var(--surface); }
.home-switch-row .hs-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-switch-row.current .hs-name { font-weight: 600; }
.home-switch-row .check-mark { color: var(--accent); flex: 0 0 auto; }
.home-switch-row .check-mark svg { width: 20px; height: 20px; }
.settings .signout { margin-top: 30px; }

/* ---------- pulse strip (used at top of detail/secondary if needed) ---------- */
.help-note { color: var(--ink-2); font-size: .875rem; padding: 0 4px; margin-top: 8px; }

/* ---------- invite / share screen ---------- */
.invite-screen .inv-hero { text-align: center; margin: 6px 0 20px; }
.inv-mark {
  display: inline-grid; place-items: center; width: 52px; height: 52px; border-radius: 15px;
  background: var(--accent-soft); color: var(--accent); margin-bottom: 12px;
}
.inv-mark svg { width: 24px; height: 24px; }
.inv-hero h1 { font-size: 1.55rem; letter-spacing: -0.02em; }
.inv-hero .lede { max-width: 32ch; margin: 6px auto 0; }

/* the vibrant code card is the share centrepiece (a Jam-style moment) */
.inv-card {
  margin: 0 0 22px; padding: 26px 20px; border-radius: 22px; text-align: center; color: #fff;
  background: linear-gradient(155deg, #0b6e54, #0f5440 55%, #073327);
  box-shadow: 0 14px 34px rgba(11, 110, 84, .30);
}
.inv-card-home { font-size: .9375rem; font-weight: 600; color: rgba(255, 255, 255, .82); }
.inv-code {
  margin: 8px 0 0; font-size: 2.35rem; font-weight: 800; line-height: 1.05;
  letter-spacing: .16em; text-indent: .16em; font-variant-numeric: tabular-nums; cursor: pointer;
}
.inv-code:focus-visible { outline: 3px solid rgba(255, 255, 255, .55); outline-offset: 4px; border-radius: 8px; }
.inv-avatars { display: flex; align-items: center; justify-content: center; margin-top: 18px; }
.inv-avatars .ava { width: 30px; height: 30px; font-size: .72rem; background: #fff; color: var(--accent); box-shadow: 0 0 0 2px #0f5440; }
.inv-avatars .ava + .ava { margin-left: -8px; }
.inv-av-label { margin-left: 10px; font-size: .8125rem; color: rgba(255, 255, 255, .9); }

.inv-actions { display: grid; gap: 10px; }
.inv-actions .btn.big { width: 100%; margin-top: 0; }
.inv-note { color: var(--ink-2); font-size: .8125rem; line-height: 1.45; text-align: center; margin: 16px auto 0; max-width: 42ch; }
.inv-reset { display: block; margin: 16px auto 0; color: var(--ink-3); font-size: .8125rem; }

/* invited banner on the auth screen (recipient may have no account yet) */
.auth-invite {
  display: flex; align-items: center; gap: 8px; width: fit-content; margin: -4px auto 16px;
  padding: 8px 14px; border-radius: 999px; background: var(--accent-soft);
  color: var(--accent-press); font-size: .875rem; font-weight: 600;
}
.auth-invite svg { width: 16px; height: 16px; }

/* ---------- toast ---------- */
#toast {
  position: fixed; left: 50%; bottom: calc(34px + var(--safe-bot));
  transform: translateX(-50%) translateY(14px);
  background: var(--ink); color: #fff; padding: 12px 20px; border-radius: var(--r-pill);
  font-size: .9375rem; font-weight: 600; letter-spacing: -0.01em;
  opacity: 0; pointer-events: none; z-index: var(--z-toast);
  transition: opacity .22s ease, transform .22s cubic-bezier(.22, 1, .36, 1);
  box-shadow: var(--shadow-pop); max-width: calc(100vw - 40px);
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------- skeletons ---------- */
.skeleton-list { display: flex; flex-direction: column; gap: 12px; margin-top: 4px; }
.sk-card, .sk-line, .sk-tile, .sk-bar {
  background: var(--surface); border-radius: var(--r-md); position: relative; overflow: hidden;
}
.sk-card { height: 84px; }
.sk-line { height: 56px; }
.sk-tile { height: 92px; }              /* mirrors an .equip-card so the grid doesn't jump on load */
.sk-bar { height: 12px; border-radius: 6px; }
.sk-group { width: 110px; margin: 24px 4px 12px; }
.eq-sk .sk-group:first-child { margin-top: 6px; }
.mh-sk { display: flex; flex-direction: column; gap: 10px; }   /* mirrors Manage>Home: label · field · card · rows */
.mh-sk .sk-group { width: 110px; margin: 14px 0 0; }
.mh-sk .sk-group:first-child { margin-top: 2px; }
/* Bare skeleton placeholders live in plain mount containers with no gap; space consecutive ones so
   they don't merge into a single solid block. (.skeleton-list already spaces via flex gap.) */
.sk-line + .sk-line, .sk-card + .sk-card, .sk-card + .sk-line, .sk-line + .sk-card { margin-top: 12px; }
/* Inside flex/grid-gap containers the sibling margin would DOUBLE the gap — reset it. Higher
   specificity than the sibling rule (0,3,0 vs 0,2,0) so it actually wins. */
.skeleton-list > .sk-card + .sk-card, .skeleton-list > .sk-line + .sk-line,
.nav-stack > .sk-card + .sk-card, .nav-stack > .sk-line + .sk-line { margin-top: 0; }
/* Manage hub + directory skeletons mirror the real nav-row/directory-row height (~74px). */
.mng-hub > .sk-card, #mh-appliances .sk-card, #mh-bills .sk-card, #choreBody .sk-card { height: 74px; }
@keyframes shimmer { to { transform: translateX(100%); } }
.sk-card::after, .sk-line::after, .sk-tile::after, .sk-bar::after {
  content: ''; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(0, 0, 0, .05), transparent);
  animation: shimmer 1.4s ease-in-out infinite;
}

/* ---------- button loading spinner ---------- */
@keyframes spin { to { transform: rotate(360deg); } }
.btn.loading, .icon-btn.loading { color: transparent !important; position: relative; pointer-events: none; }
.btn.loading::after, .icon-btn.loading::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 18px; height: 18px;
  margin: -9px 0 0 -9px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .5); border-top-color: transparent;
  animation: spin .6s linear infinite;
}
.btn.ghost.loading::after, .btn.small.loading::after, .icon-btn.loading::after {
  border-color: rgba(0, 0, 0, .25); border-top-color: transparent;
}

/* pull-to-refresh spinner — follows the drag (JS sets transform/opacity), spins while refreshing */
#ptr {
  position: fixed; top: calc(6px + var(--safe-top)); left: 50%; z-index: 40; pointer-events: none;
  width: 32px; height: 32px; display: grid; place-items: center;
  transform: translate(-50%, -44px); opacity: 0;
  background: var(--bg); border-radius: 50%; box-shadow: var(--shadow-card);
}
.ptr-ring { width: 20px; height: 20px; box-sizing: border-box; border-radius: 50%; border: 2.5px solid var(--line-2); border-top-color: var(--accent); }
#ptr.ready .ptr-ring { border-color: var(--accent-soft); border-top-color: var(--accent); }
#ptr.spin { transform: translate(-50%, 16px) !important; opacity: 1 !important; }
#ptr.spin .ptr-ring { animation: spin .7s linear infinite; }

/* ---------- view transition (state-conveying, restrained) ---------- */
@keyframes viewIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.screen.enter { animation: viewIn .26s cubic-bezier(.22, 1, .36, 1) both; }

@keyframes rowIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.stagger { animation: rowIn .3s cubic-bezier(.22, 1, .36, 1) both; animation-delay: calc(var(--i, 0) * 34ms); }

/* ---------- larger screens: a touch more air ---------- */
/* ---------- Manage > Home: appliances as owned objects (supply + setup, not the task runway) ----------
   The flat identical grid is gone. A "To buy" band answers "should I buy something?" at a glance;
   below it, appliances group by home system with a real per-type icon and one supply/setup line. */
.ap-section { margin-top: 6px; }
.ap-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 24px 4px 12px; }
.ap-head .btn.small { padding: 6px 12px; }

/* Header actions — a round search toggle sits beside the Add pill. */
.ap-head-actions { display: inline-flex; align-items: center; gap: 8px; }
.ap-head-btn {
  width: 36px; height: 36px; flex: 0 0 auto; border-radius: 50%; border: 1px solid var(--line-2);
  background: transparent; color: var(--ink); cursor: pointer; display: grid; place-items: center;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.ap-head-btn svg { width: 18px; height: 18px; }
.ap-head-btn:hover { background: var(--surface); }
.ap-head-btn.active { background: var(--accent-soft); border-color: transparent; color: var(--accent); }

/* Find — collapsed by default, expands on tap of the header toggle. Focus uses an INSET ring so the
   glow isn't clipped by the overflow:hidden the height animation needs. */
.ap-search {
  position: relative; max-height: 0; opacity: 0; margin: 0; overflow: hidden;
  transition: max-height .28s cubic-bezier(.22, 1, .36, 1), opacity .2s ease, margin-bottom .28s ease;
}
.ap-search.open { max-height: 60px; opacity: 1; margin-bottom: 16px; }
/* The field itself is shared with the Manage finder (.mf) below — one look for "search" across the
   app. Only the appliance version collapses; the Manage ones are always visible. */
.ap-search-ico, .mf-ico { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); display: inline-flex; color: var(--ink-3); pointer-events: none; }
.ap-search-ico svg, .mf-ico svg { width: 18px; height: 18px; }
.ap-search-in, .mf-in {
  width: 100%; font: inherit; font-size: 1rem; color: var(--ink);
  background: var(--bg); border: 1px solid var(--line-2); border-radius: var(--r-md);
  padding: 12px 40px 12px 42px;
  -webkit-appearance: none; appearance: none; transition: border-color .15s ease, box-shadow .15s ease;
}
.ap-search-in::placeholder, .mf-in::placeholder { color: var(--ink-3); }
.ap-search-in:focus, .mf-in:focus { outline: none; border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.ap-search-in::-webkit-search-cancel-button, .ap-search-in::-webkit-search-decoration,
.mf-in::-webkit-search-cancel-button, .mf-in::-webkit-search-decoration { -webkit-appearance: none; display: none; }
.ap-search-clear, .mf-clear {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; border: none; background: none; cursor: pointer; color: var(--ink-3);
  display: grid; place-items: center; border-radius: 50%; transition: color .15s ease, background .15s ease;
}
.ap-search-clear svg, .mf-clear svg { width: 16px; height: 16px; }
.ap-search-clear:hover, .mf-clear:hover { color: var(--ink); background: var(--surface); }
.ap-search-clear[hidden], .mf-clear[hidden] { display: none; }
.ap-search-meta, .mf-meta { margin: -4px 4px 12px; font-size: .8125rem; font-weight: 600; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.ap-search-empty, .mf-empty {
  padding: 22px 18px; text-align: center; color: var(--ink-2); font-size: .9375rem;
  background: var(--bg); border-radius: 14px; box-shadow: var(--shadow-card);
}

/* Manage finder — the glyph WIDENS into the field, in place. Tapping a button in the header and
   having a box appear somewhere else reads as two unrelated things; growing the control you
   touched keeps the action and its result in one spot (the Spotify / iOS nav-bar move).
   The slot is a flex item that goes from icon-width to filling the header row, so the field
   ends up exactly where the icon was and the back button stays reachable throughout. */
.mf-slot {
  position: relative; flex: 0 1 auto; width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: flex-end;
  transition: width .3s cubic-bezier(.22, 1, .36, 1);
}
.mf-slot.open { width: 100%; }
.mf {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  width: 100%; opacity: 0; pointer-events: none;
  transition: opacity .18s ease;
}
.mf-slot.open .mf { opacity: 1; pointer-events: auto; }
/* the glyph fades as the field takes its place */
/* Taken out of flow entirely, not just faded: the field sits ON TOP of the glyph, and against the
   translucent hero-band field a merely-transparent button still ghosted through as a dark disc. */
.mf-slot.open .mf-toggle { display: none; }
.mf-toggle { transition: opacity .16s ease; }
/* the field is shorter in a header than in a form — match the 36px control height */
.mf .mf-in { padding: 8px 38px 8px 38px; font-size: 1rem; border-radius: 999px; }
.mf .mf-ico { left: 12px; }
.mf .mf-clear { right: 4px; }
.mf-results { display: block; margin-top: 2px; }
.mf-empty[hidden] { display: none; }

/* the dashboard's field sits on the coloured hero band, so it borrows the band's glass treatment
   instead of the white-on-white form styling */
/* no backdrop-filter here: over the band's gradient it renders a dark lens artifact at the pill's
   rounded cap (and it's an expensive effect on a screen that scrolls). A flat translucent white
   reads the same at this size. */
.mf-band .mf-in {
  background-color: rgba(255, 255, 255, .18); border-color: transparent; color: #fff;
}
.mf-band .mf-in::placeholder { color: rgba(255, 255, 255, .70); }
.mf-band .mf-in:focus { background-color: rgba(255, 255, 255, .24); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .5); }
.mf-band .mf-ico, .mf-band .mf-clear { color: rgba(255, 255, 255, .78); }
.mf-band .mf-clear:hover { color: #fff; background: rgba(255, 255, 255, .18); }
/* the date + home name step aside while the field is open */
.dash-top .masthead { transition: opacity .18s ease; min-width: 0; }
.dash-top.searching .masthead { opacity: 0; flex: 0 1 0; overflow: hidden; }
.dash-top.searching .top-actions > .icon-btn { display: none; }
/* .top-actions is content-sized, so the slot's width:100% would resolve against ~64px and the
   field would expand to nothing. While searching the actions row takes the freed width. */
.dash-top.searching .top-actions { flex: 1 1 auto; }
.dash-top.searching { align-items: center; }
/* grow the slot with flex, not `width: 100%`: as a flex item in a row whose own width is
   resolved during layout, the percentage was collapsing back to the 36px icon box */
.dash-top.searching .mf-slot { flex: 1 1 auto; width: auto; }
/* second results group: the things you manage, under the tasks */
.results-sub { margin: -6px 4px 10px; font-size: .8125rem; color: var(--ink-3); }
.res-manage { margin-top: 2px; }

/* headers make room: the title yields while searching */
.top .spacer { display: flex; align-items: center; justify-content: flex-end; }
.top.searching { gap: 8px; }
.top.searching .spacer { flex: 1 1 auto; width: auto; }
.top.searching .mid { flex: 0 1 0; opacity: 0; overflow: hidden; white-space: nowrap; transition: opacity .16s ease; }
.mng-head-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.mng-head-top .mng-h1 { transition: opacity .18s ease; min-width: 0; }
/* the title yields its WIDTH as well as its ink, or the field expands into a half-row and the
   empty space where the invisible heading still sits reads as a misalignment */
.mng-head-top.searching .mng-h1 { opacity: 0; flex: 0 1 0; overflow: hidden; white-space: nowrap; }
.mng-head.searching .lede { opacity: 0; transition: opacity .16s ease; }
@media (prefers-reduced-motion: reduce) {
  .mf-slot, .mf, .mf-toggle, .top.searching .mid, .mng-head-top .mng-h1 { transition: none; }
}

/* "To buy" band — the cross-appliance shopping roll-up. Helpful, not alarming: a warm surface, a
   copyable list, per-item Buy / Got-it. This is the moment the screen earns its keep. */
/* A quiet shopping list, not a promo box: plain white card in the same language as the rows, tick
   circles to check items off, a text Buy link, and Low/Soon as small text. No cream fill, no filled
   buttons, minimal color. */
.ap-tobuy { background: var(--bg); border-radius: 18px; box-shadow: var(--shadow-card); overflow: hidden; margin-bottom: 22px; }
.ap-tobuy-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px 11px; }
.ap-tobuy-title { font-weight: 680; font-size: 1.0625rem; letter-spacing: -0.01em; color: var(--ink); }
.ap-tobuy-n { color: var(--ink-3); font-weight: 600; margin-left: 7px; font-variant-numeric: tabular-nums; }
.ap-copy {
  display: inline-flex; align-items: center; gap: 6px; background: none; border: none; cursor: pointer;
  color: var(--ink-2); font: inherit; font-size: .875rem; font-weight: 600; padding: 4px; border-radius: 8px;
  transition: color .15s ease;
}
.ap-copy svg { width: 15px; height: 15px; }
.ap-copy:hover { color: var(--ink); }
.ap-copy.done { color: var(--ok); }

.ap-buy { display: flex; align-items: center; gap: 13px; padding: 12px 16px; border-top: 1px solid var(--line); }
.ap-tick {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%; border: 1.5px solid var(--line-2);
  background: var(--bg); display: grid; place-items: center; padding: 0; cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.ap-tick svg { width: 14px; height: 14px; color: #fff; opacity: 0; }
.ap-tick svg path { stroke-dasharray: 26; stroke-dashoffset: 26; }
.ap-tick:hover { border-color: var(--ink-3); }
/* the satisfying moment: the circle springs and the check draws itself in */
.ap-buy.ticked .ap-tick { background: var(--accent); border-color: var(--accent); animation: ap-tick-pop .34s cubic-bezier(.34, 1.56, .64, 1); }
.ap-buy.ticked .ap-tick svg { opacity: 1; }
.ap-buy.ticked .ap-tick svg path { animation: ap-check-draw .3s .05s ease forwards; }
@keyframes ap-tick-pop { 0% { transform: scale(1); } 42% { transform: scale(.8); } 100% { transform: scale(1); } }
@keyframes ap-check-draw { to { stroke-dashoffset: 0; } }
/* the line is a button now (tap → "how many have I got?"), so strip the button chrome and keep
   the receipt-like look; only the press state hints that it's live */
.ap-buy-info {
  flex: 1; min-width: 0; background: none; border: none; padding: 0; font: inherit;
  color: inherit; text-align: left; cursor: pointer; border-radius: 10px;
}
.ap-buy-info:active { background: rgba(0, 0, 0, .04); }
.ap-buy-info:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }

/* stock sheet — one count per appliance the supply serves */
.stock-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 12px 2px; }
.stock-row + .stock-row { border-top: 1px solid var(--line); }
.stock-where { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.stock-where strong { font-size: 1rem; font-weight: 620; letter-spacing: -0.01em; }
.stock-where em { font-style: normal; font-size: .8125rem; color: var(--ink-3); }
.stepper.stock-step { flex: 0 0 auto; }
.stepper.stock-step .step-n { min-width: 34px; font-size: 1.125rem; }
.stock-note { font-size: .875rem; color: var(--ink-2); line-height: 1.45; padding: 10px 2px 2px; text-wrap: pretty; }
.btn.stock-open { width: 100%; margin-top: 10px; }
.ap-buy-name { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; font-weight: 600; font-size: 1rem; letter-spacing: -0.01em; }
.ap-buy-qty { color: var(--ink-2); font-weight: 600; font-variant-numeric: tabular-nums; }
.ap-buy-spec { color: var(--ink-2); font-weight: 500; font-size: .875rem; }
.ap-buy-meta { display: flex; align-items: center; gap: 6px; margin-top: 2px; font-size: .8125rem; color: var(--ink-2); }
.ap-src { font-size: .6875rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.ap-src.low { color: var(--danger); }
.ap-src.soon { color: var(--warn); }
.ap-buy-link {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px; background: none; border: none;
  cursor: pointer; color: var(--accent); font: inherit; font-size: .9375rem; font-weight: 620; padding: 6px 2px;
  transition: color .15s ease;
}
.ap-buy-link svg { width: 14px; height: 14px; }
.ap-buy-link:hover { color: var(--accent-press); text-decoration: underline; }
.ap-buy.done { opacity: 0; transform: translateX(26px); transition: opacity .3s ease, transform .3s cubic-bezier(.4, 0, .2, 1); }

/* The reward: clearing the list blooms this in, and the check draws itself. Reassurance you earned. */
.ap-stocked {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px; margin-bottom: 22px;
  background: var(--ok-soft); border-radius: 14px; color: color-mix(in srgb, var(--ok) 88%, var(--ink));
  font-size: .9375rem; font-weight: 560;
  animation: ap-bloom .55s cubic-bezier(.22, 1, .36, 1);
}
.ap-stocked svg { width: 20px; height: 20px; color: var(--ok); flex: 0 0 auto; }
.ap-stocked svg path { stroke-dasharray: 26; stroke-dashoffset: 26; animation: ap-check-draw .5s .12s ease forwards; }
@keyframes ap-bloom { from { opacity: 0; transform: translateY(7px) scale(.99); } to { opacity: 1; transform: none; } }

/* Gentle entrance — the band and each system group rise in, lightly staggered. */
.ap-anim { animation: ap-rise .5s cubic-bezier(.22, 1, .36, 1) both; animation-delay: calc(var(--i, 0) * 55ms); }
@keyframes ap-rise { from { opacity: 0; transform: translateY(11px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .ap-anim, .ap-stocked, .ap-stocked svg path, .ap-buy.ticked .ap-tick, .ap-buy.ticked .ap-tick svg path { animation: none; }
  .ap-anim { opacity: 1; transform: none; }
  .ap-tick svg path { stroke-dashoffset: 0; }
  .ap-buy.done { transition: opacity .12s ease; transform: none; }
}

/* System groups — the house as an owner reads it. */
.ap-group { margin-bottom: 20px; }
.ap-group-head {
  display: flex; align-items: center; gap: 9px; margin: 0 4px 10px;
  font-size: .8125rem; font-weight: 680; letter-spacing: .01em; color: var(--ink-2); text-transform: uppercase;
}
.ap-group-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.ap-group-n { color: var(--ink-3); font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: 0; }
.ap-rows { display: grid; gap: 10px; }

.ap-row {
  width: 100%; display: flex; align-items: center; gap: 13px; text-align: left; cursor: pointer;
  background: var(--bg); border: none; font: inherit; color: inherit;
  padding: 13px 15px; border-radius: 16px; box-shadow: var(--shadow-card);
  transition: background .15s ease, transform .08s ease;
}
.ap-row:hover { background: var(--surface); }
.ap-row:active { transform: scale(.99); }
.ap-row[hidden] { display: none; }   /* [hidden] alone loses to display:flex; scope it back on */
.ap-ico {
  display: inline-grid; place-items: center; flex: 0 0 auto; width: 42px; height: 42px; border-radius: 12px;
  color: var(--sys); background: color-mix(in srgb, var(--sys) 13%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sys) 14%, transparent);
}
.ap-ico svg { width: 23px; height: 23px; display: block; }
.ap-body { flex: 1; min-width: 0; }
.ap-name { display: block; font-weight: 640; font-size: 1.0625rem; letter-spacing: -0.012em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-status { display: flex; align-items: center; gap: 6px; margin-top: 2px; font-size: .9rem; color: var(--ink-2); }
.ap-status.buy { color: var(--warn); font-weight: 580; }
.ap-status.setup { color: var(--ink-3); }
.ap-flag { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.ap-flag.buy { background: var(--warn); }
.ap-flag.setup { background: none; box-shadow: inset 0 0 0 1.5px var(--ink-3); }
.ap-chev { color: var(--ink-3); display: inline-flex; flex: 0 0 auto; }
.ap-chev svg { width: 18px; height: 18px; }

/* Appliance object page — the asset profile ("set up & update things"): a compact spec sheet. */
.ap-details { background: var(--bg); border-radius: 16px; box-shadow: var(--shadow-card); padding: 6px 16px 16px; }
.ap-details-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; }
/* Labels in a pair aren't the same length — "Serial number" wraps to two lines next to "Model" at
   phone width — so let each cell stretch and pin its control to the bottom. The inputs then line
   up across the row however the labels fall. */
.ap-details-grid .field { margin: 12px 0 0; display: flex; flex-direction: column; }
.ap-details-grid .field > input,
.ap-details-grid .field > select,
.ap-details-grid .field > textarea { margin-top: auto; }
.ap-details-grid .ap-span { grid-column: 1 / -1; }
/* Two ~150px columns can't hold their own content on a phone: "Serial number" wraps, its
   placeholder clips to "Optiona", and the warranty select shows "Non". Pairs are a nicety —
   readable fields are not — so below 420px everything gets the full width. */
@media (max-width: 420px) {
  .ap-details-grid { grid-template-columns: 1fr; }
}
.ap-details-grid textarea { resize: vertical; min-height: 44px; }
.ap-details-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 16px; flex-wrap: wrap; min-height: 22px; }
/* Autosave status, where the Save button used to be. Silent at rest — it only speaks while
   writing, briefly on success, and stays put (tappable) if a write fails. */
.save-state { font-size: .8125rem; font-weight: 600; color: var(--ink-3); margin-left: auto; transition: opacity .18s ease; }
.save-state:empty { opacity: 0; }
.save-state.saving { color: var(--ink-2); }
.save-state.saved { color: var(--ok); }
.save-state.saved::before { content: '✓ '; }
.save-state.failed { color: var(--danger); cursor: pointer; text-decoration: underline; }
.ap-warranty-slot:empty { display: none; }
.ap-warranty {
  display: inline-flex; align-items: center; font-size: .875rem; font-weight: 560;
  padding: 5px 11px; border-radius: 999px; background: var(--ok-soft); color: color-mix(in srgb, var(--ok) 86%, var(--ink));
}
.ap-warranty.soon { background: var(--warn-soft); color: var(--warn); }
.ap-warranty.expired { background: var(--surface); color: var(--ink-2); }
.ap-details-foot .btn.primary { margin-left: auto; }

@media (min-width: 480px) {
  .standfirst { font-size: 2.25rem; }
  .screen { padding-left: 28px; padding-right: 28px; }
}

/* ============ Tablet & larger — iPad portrait (~768–834), landscape (~1024–1366) ============
   Phones stay a focused single column: this block starts at 768px, so an iPad in a narrow
   split-view still gets the phone layout. On a real tablet the column widens, the tab bar becomes
   a compact centered floating bar (not tabs sprayed across the whole screen), and independent-card
   surfaces — the manage hub, driver/area lists, dashboard task cards, care groups, photos — flow
   into columns. Priority order is preserved (grids fill left-to-right, top-to-bottom); reading and
   forms keep a comfortable measure centered in the wider column. */
@media (min-width: 768px) {
  :root { --maxw: 820px; }

  .screen { padding-left: 40px; padding-right: 40px; }
  .hero-band { padding-left: 40px; padding-right: 40px; }
  .dash-body { padding-left: 40px; padding-right: 40px; }

  /* The tab bar already floats at every size; give it a touch more room on the wide canvas. */
  .tabbar { width: min(460px, calc(100% - 48px)); }

  /* Independent-card stacks (manage hub, home/area/pet/vehicle lists) -> two columns. */
  .nav-stack { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; align-items: stretch; }
  /* Hubs stay a single centered column even on tablet — nav, not a dense list. */
  .nav-stack.mng-hub { grid-template-columns: 1fr; margin-inline: auto; }

  /* Appliance rows flow two-up within each system group; the to-buy band stays full width. */
  .ap-rows { grid-template-columns: repeat(2, 1fr); }

  /* Dashboard task lists -> a two-column grid of task cards. Rows navigate (open a sheet) and don't
     expand inline, so a grid is safe; the connected list card becomes separate cards. */
  .dash .list {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
    background: transparent; box-shadow: none; border-radius: 0; overflow: visible;
  }
  .dash .list > .row { border-bottom: none; border-radius: 14px; box-shadow: var(--shadow-card); }

  /* Care screens: group cards (Grooming / Lawn & Yard / …) sit side by side. Multi-column keeps each
     group's connected list intact (break-inside: avoid); an expanding row reflows within its column. */
  #pet-care-groups, #ar-care-groups, #veh-care-groups { column-count: 2; column-gap: 18px; }
  #pet-care-groups > .pet-care-group, #ar-care-groups > .pet-care-group, #veh-care-groups > .pet-care-group { break-inside: avoid; margin: 0 0 18px; }

  /* More photos per row on the wider canvas. */
  .photo-grid { grid-template-columns: repeat(4, 1fr); }

  /* Detail & form content keeps a comfortable measure, centered in the wider column. Pet/Area bodies
     stay a touch wider to hold their two-column care groups; the appliance body is a single list. */
  #petBody, #arBody { max-width: 760px; margin-inline: auto; }
  #apBody { max-width: 680px; margin-inline: auto; }
  .form-group { max-width: 640px; margin-inline: auto; }

  /* Transient pickers stay phone-sized, not stretched to the wide column. */
  .content-sheet, .sheet { max-width: 600px; }
}

@media (min-width: 1200px) {
  :root { --maxw: 940px; }
  .nav-stack { grid-template-columns: repeat(3, 1fr); }
  .ap-rows { grid-template-columns: repeat(3, 1fr); }
  .photo-grid { grid-template-columns: repeat(5, 1fr); }
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .screen.enter, .stagger, .row.leaving { animation: none; }
  .sk-card::after, .sk-line::after, .sk-tile::after, .sk-bar::after { animation: none; }
  .row.leaving { display: none; }
  .btn.loading::after, .icon-btn.loading::after { animation: spin 1.2s linear infinite; }
  * { transition-duration: .01ms !important; }
}

/* ---------- touch: neutralize sticky :hover ----------
   On touch devices :hover "sticks" to the element under the last tap, so tapping a card and
   navigating to the card at the same position on the next screen leaves it looking pre-selected.
   Reset hover fills to each element's default where there's no real hovering pointer; :active still
   gives tap feedback. Placed at end-of-file so it wins the source-order tie over the base :hover.
   Triggered on `pointer: coarse` OR `hover: none`: a phone is always coarse-pointer, so this still
   fires on devices that mis-report `hover: hover` (where a plain `(hover: none)` guard leaked). */
@media (hover: none), (pointer: coarse) {
  .nav-row:hover, .home-switch-row:hover, .ap-row:hover { background: var(--bg); }
  .opt-row:hover { background: transparent; }
}

/* ---------------------------------------------------------------------------
   Date & time inputs — normalized everywhere, not just inside .field.

   Two native behaviours make an empty date field look broken, and both showed up
   on the appliance "Purchased" row (a short blank pill beside a full-height select):

   1. iOS Safari gives an EMPTY date/month input's value area no height at all, so
      the control renders shorter than its neighbours until a date is picked. Giving
      the value area a min-height fixes it regardless of the field's own padding —
      which is why this is expressed on the inner pseudo-elements rather than as a
      hardcoded min-height that only matched .field's 14px padding.
   2. An empty date input renders completely blank on iOS — no format hint, nothing
      that says "tap me". The calendar glyph gives it an affordance in every browser.

   The selector list names the off-.field date inputs explicitly (.sp-dateinput,
   .anchor-date) so the glyph reaches them too.

   NOTE for future edits: every input rule in this file now sets `background-color`,
   never the `background` shorthand. The shorthand resets background-image, so a rule
   like `.form-group.sched .field input { background: var(--canvas) }` — which only
   wants to change a colour — silently deleted this glyph anywhere inside a form group.
   Keep using background-color on inputs.
   --------------------------------------------------------------------------- */
input[type="date"], input[type="month"], input[type="week"],
input[type="time"], input[type="datetime-local"],
.sp-datebox .sp-dateinput, .care-anchor .anchor-date {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8a8e' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='3'/%3E%3Cpath d='M8 3v4M16 3v4M3 10h18'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  background-size: 17px 17px;
  padding-right: 40px;
  -webkit-appearance: none; appearance: none;
}
/* The value area must hold a line even when empty (bug 1). The margin reset matters as much as the
   min-height: the value element carries a default margin that made date fields land 2px taller than
   the text inputs beside them — visible as a misaligned row in a two-column grid. */
input[type="date"]::-webkit-date-and-time-value,
input[type="month"]::-webkit-date-and-time-value,
input[type="week"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value { min-height: 1.4em; line-height: 1.4; margin: 0; text-align: left; }
input[type="date"]::-webkit-datetime-edit,
input[type="month"]::-webkit-datetime-edit,
input[type="week"]::-webkit-datetime-edit,
input[type="time"]::-webkit-datetime-edit,
input[type="datetime-local"]::-webkit-datetime-edit { line-height: 1.4; padding: 0; margin: 0; }
input::-webkit-datetime-edit-fields-wrapper { padding: 0; margin: 0; }
/* an unset segment is a hint, not content — quieten it so a filled date reads as the real value */
input::-webkit-datetime-edit-text { color: var(--ink-3); padding: 0 1px; }
input:not(:focus)::-webkit-datetime-edit-year-field[aria-valuenow=""],
input:not(:focus)::-webkit-datetime-edit-month-field[aria-valuenow=""],
input:not(:focus)::-webkit-datetime-edit-day-field[aria-valuenow=""] { color: var(--ink-3); }
/* our glyph replaces the native indicator, which we stretch over the field so a tap anywhere
   opens the picker (Chrome). iOS opens its own picker on focus, so nothing is lost there. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="week"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  position: absolute; inset: 0; width: auto; height: auto; margin: 0; padding: 0;
  opacity: 0; cursor: pointer;
}
input[type="date"], input[type="month"], input[type="week"],
input[type="time"], input[type="datetime-local"] { position: relative; }

/* "Where is it?" memory — the places you've already used, one tap away. Free text still wins:
   type anything and it joins the list next time. */
.loc-chips { display: flex; flex-wrap: wrap; gap: 7px; margin: -8px 0 18px; }
.loc-chip {
  border: 1px solid var(--line-2); background: var(--bg); color: var(--ink-2);
  font: inherit; font-size: .875rem; font-weight: 550; padding: 7px 13px;
  border-radius: 999px; cursor: pointer; transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.loc-chip:hover { background: var(--surface); color: var(--ink); }
.loc-chip.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-press); }
