/* app.perdura.org — Perdura brand, tuned for older eyes (builder-ux-spec §1). */
:root {
  /* Perdura reskin (BUILDER-24 §6, short-term token swap): legacy names, plum
     values — forest=plum-600 (6.7:1 on cream, same as the old forest), forest-deep=
     plum-800, sage=plum-400 (3.2:1 — borders and marks only, never body text),
     sage-wash=wisteria. Semantic --danger/--warn/--success stay green/amber/ember;
     the honest rename to --accent-* waits for Phase 4. */
  /* Type stack as a token, because the `font:` SHORTHAND resets the family.
     Any rule written as `font: 600 .8rem/1.2 sans-serif` silently opts out of
     the body stack and renders in the generic sans (Helvetica on macOS), so the
     step nav was in a different typeface from the app around it. Naming it
     means a shorthand can say var(--sans) and stay in the system. */
  --sans:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --serif:ui-serif,Georgia,'Times New Roman',serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  --forest:#5d4a78; --forest-deep:#2e2439; --sage:#8f7cc0; --sage-wash:#e7e1f2;
  --cream:#f5f2ea; --paper:#fbf9f4; --ink:#26332b; --muted:#59685d; --line:#e5dfd1;
  --clay:#8a5138; --ember:#a1332b;
  /* BUILDER-21 Part A: one named radius scale (same pixels as before, now
     consistent) — sm=inputs/.err, md=.btn, lg=.card. --radius kept as an
     alias of --radius-lg so nothing that reads it directly has to change. */
  --radius-sm:10px; --radius-md:12px; --radius-lg:14px; --radius:var(--radius-lg);
  /* Semantic aliases — same values as today's ad-hoc ones, now named + reused
     by .err/focus below instead of repeating the hex/color-mix per spot. */
  --danger:var(--ember); --danger-wash:#fbeae8; --danger-line:#f0cfcb; --success:#3d5c47;
  /* BUILDER-2 SW-1: a third semantic tier (warn) for "in progress" / "action
     needed but not broken" — was a one-off inline #c0842e before; named now so
     the publish banner's amber states share one source. */
  --warn:#96650f; --warn-wash:#faf1e0; --warn-line:#ecd8ab;
  --focus-ring:color-mix(in srgb,var(--forest) 55%,#fff);
  /* ONE page gutter for header + content (they were misaligned on phones:
     head .9rem vs wrap 1.25rem). Phones override to 1rem below. */
  --gutter:1.25rem; --pad-panel:1.1rem 1.3rem;
  --step--1:clamp(.9rem,.86rem+.2vw,1rem); --step-0:clamp(1.125rem,1.09rem+.16vw,1.19rem);
  --step-1:clamp(1.35rem,1.25rem+.5vw,1.7rem); --step-2:clamp(1.7rem,1.5rem+1vw,2.3rem);
}
/* Contrast follows the OS/browser setting — no in-app toggle. Text size is
   rem-based throughout, so browser zoom / font-size settings scale everything. */
@media (prefers-contrast: more){
  :root{
    --ink:#131a15; --muted:#2e3a32; --line:#8d867a;
    --cream:#ffffff; --paper:#ffffff; --sage-wash:#e2d9f0;
    --forest:#4a3b60; --forest-deep:#241c2e;
  }
  .mut{color:var(--muted, #2e3a32)}
}
*,*::before,*::after{box-sizing:border-box} *{margin:0}
body{font-family:var(--sans);font-size:var(--step-0);
  line-height:1.6;color:var(--ink);background:var(--cream);-webkit-font-smoothing:antialiased}
h1,h2,h3{font-family:var(--serif);font-weight:600;line-height:1.15;text-wrap:balance}
h1{font-size:var(--step-2)} h2{font-size:var(--step-1)}
/* The `hidden` attribute must always win.
   Any rule that sets `display` on a class beats the attribute's default
   display:none, so a hidden element renders anyway. That has now shipped three
   times: .unpub-confirm left a confirmation box permanently open, .assist left
   AI chips showing on the story step, and .save-pill put an empty lozenge in the
   corner of every page in the app.
   83 classes in this file set display and could do it again, so this is the one
   place to fix it rather than 83. `!important` is deliberate and is the standard
   treatment for [hidden]; the per-class guards below stay as a record of where
   it has already hurt. Asserted in nav.spec.ts. */
[hidden]{display:none !important}
p{text-wrap:pretty} a{color:var(--forest)} img{max-width:100%;display:block}
:focus-visible{outline:3px solid var(--focus-ring);outline-offset:2px;border-radius:4px}
.wrap{max-width:44rem;margin-inline:auto;padding:0 var(--gutter)}
.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:clamp(1.4rem,4vw,2.2rem)}
label{display:block;font-weight:600;font-size:var(--step--1);margin-bottom:.35rem}
/* Text-like fields fill their row; checkboxes and radios must NOT — the global
   width:100% used to inflate them into a full-width box that shoved the label
   into a one-word column (email prefs, review options). Excluding them here
   fixes it at the source so every current and future checkbox/radio is correct
   without a per-spot override. */
input:not([type=checkbox]):not([type=radio]),textarea,select{font:inherit;color:var(--ink);width:100%;background:#fff;
  border:1px solid var(--line);border-radius:var(--radius-sm);padding:.75rem .9rem}
input[type=checkbox],input[type=radio]{accent-color:var(--forest);width:auto;flex:none;margin:0}
input:focus-visible,textarea:focus-visible{outline:2px solid var(--forest);outline-offset:1px;border-color:var(--forest)}
textarea{resize:vertical;min-height:10rem;line-height:1.7}
.field{margin-bottom:1.15rem} .opt{font-weight:400;color:var(--muted)}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;font-weight:600;
  font-size:var(--step-0);padding:.8rem 1.4rem;border-radius:var(--radius-md);border:0;cursor:pointer;
  background:var(--forest);color:#fff;text-decoration:none;min-height:44px}
.btn:hover{filter:brightness(1.08)} .btn:disabled{opacity:.65;cursor:default}
/* Ghost variants draw their stroke as an inset shadow, not a border — a border
   added 3px of height next to a solid .btn at the same padding. */
.btn-ghost{background:transparent;color:var(--forest);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--forest) 35%,#fff)}
.err{color:var(--danger);font-size:var(--step--1);background:var(--danger-wash);border:1px solid var(--danger-line);
  border-radius:var(--radius-sm);padding:.6rem .8rem;margin-bottom:1rem}
.err:empty{display:none}
.saved{color:var(--muted);font-size:var(--step--1)}
/* BUILDER-22: the date-echo's future/impossible-order note, tokenized —
   was an inline style.color='var(--ember,var(--ember, #a1332b))' set from JS. Color only,
   matching the original exactly (no other property changed = no visual
   regression beyond the token swap itself). */
.date-echo.warn{color:var(--danger)}
.steps{list-style:none;padding:0;display:flex;gap:.5rem;flex-wrap:wrap;margin:0 0 1.4rem}
.steps a{display:inline-flex;align-items:center;gap:.4rem;text-decoration:none;color:var(--muted);white-space:nowrap;
  font-size:var(--step--1);font-weight:600;padding:.4rem .8rem;border-radius:999px;background:var(--paper);border:1px solid var(--line)}
.steps .on a{background:var(--sage-wash);color:var(--forest);border-color:transparent}
.steps .done a{color:var(--forest);border-color:color-mix(in srgb,var(--sage) 60%,#fff)}
.steps .step-check{color:var(--forest)}
/* Five pills on one row down to small tablets — numbers dropped, so trim chrome.
   Trimmed chrome must not trim the finger: hold the 44px tap floor on touch sizes. */
@media (max-width:54rem){
  .steps{gap:.35rem}
  .steps a{padding:.35rem .6rem;gap:.3rem;font-size:calc(var(--step--1) * .94);min-height:2.75rem}
}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* Review checklist — mark | label + summary on one line, actions on their own
   quiet row beneath (never mid-sentence). */
.review-list{list-style:none;padding:0;margin:0;display:flex;flex-direction:column}
.review-list li{display:flex;gap:.7rem;align-items:flex-start;padding:.65rem 0;border-top:1px solid var(--line)}
.review-list li:first-child{border-top:0;padding-top:.15rem}
.review-mark{flex:none;width:1.4rem;height:1.4rem;border-radius:50%;display:inline-flex;align-items:center;
  justify-content:center;font-size:.85rem;font-weight:700;background:var(--cream);color:var(--muted);
  border:1px solid var(--line);transform:translateY(.15rem)}
.review-mark.ok{background:var(--sage-wash);color:var(--forest);border-color:transparent}
.review-body{display:flex;flex-direction:column;min-width:0}
.review-line{margin:0;display:flex;gap:.35rem .7rem;align-items:baseline;flex-wrap:wrap}
.review-step{font-weight:600;color:var(--forest);text-decoration:none}
.review-step:hover{text-decoration:underline}
.review-note{font-size:var(--step--1)}
.review-actions{display:flex;gap:.5rem;flex-wrap:wrap;margin:.55rem 0 .1rem}
.review-actions-lead{flex-basis:100%;font-size:var(--step--1);color:var(--muted)}
/* Quiet action chips; ✦ marks the AI one (same grammar as the story toolbox). */
.chip{display:inline-flex;align-items:center;gap:.35rem;padding:.3rem .8rem;min-height:34px;border-radius:999px;
  border:1px solid var(--line);background:var(--paper);color:var(--forest);font:inherit;font-size:var(--step--1);
  font-weight:600;text-decoration:none;cursor:pointer}
.chip:hover{border-color:var(--sage);background:var(--sage-wash)}
.chip:focus-visible{outline:2px solid var(--forest);outline-offset:2px}
.chip:disabled{opacity:.6;cursor:default}
.chip-ai{border-color:color-mix(in srgb,var(--clay) 40%,#fff);color:var(--clay)}
.chip-ai:hover{border-color:var(--clay);background:color-mix(in srgb,var(--clay) 8%,#fff)}

/* Live-status light — BUILDER-2 SW-1: the honest publish-state banner. State
   is word (#live-text) + SHAPE (this ::before glyph) + color, never color
   alone (ux-ui-practices.md, colorblind-safe). The dot classes themselves are
   set by the existing live-check/publish JS, unchanged — this only adds the
   glyph + the banner-level color response via :has(), so no script edits were
   needed to make the container itself reflect state. */
.live-status{display:flex;align-items:center;gap:.55rem;font-weight:600;margin:0}
.live-dot{width:.8rem;height:.8rem;border-radius:50%;background:var(--line);flex:none;position:relative}
.live-dot::before{content:"";position:absolute;inset:-.5rem;display:flex;align-items:center;justify-content:center;
  font-size:1rem;line-height:1}
.live-dot.up{background:var(--success);box-shadow:0 0 0 4px color-mix(in srgb,var(--success) 18%,transparent)}
.live-dot.up::before{content:"✓"}
.live-dot.building{background:#b8860b;animation:live-pulse 1.6s ease-in-out infinite}
.live-dot.building::before{content:"◐"}
.live-dot.down{background:var(--ember)}
.live-dot.down::before{content:"⚠"}
@keyframes live-pulse{50%{opacity:.45}}
@media (prefers-reduced-motion: reduce){.live-dot.building{animation:none}}

/* The banner itself — one prominent, honest status card at the top of a
   published Review page (relocated from the buried Settings card). Color
   follows the SAME classes the script already sets on #live-dot (:has(), no
   extra JS needed for this part) plus [data-unpub] (server-rendered from
   hasUnpublished) to tell "live & current" (success) apart from "live but you
   have unpublished edits" (warn) — both carry .live-dot.up, so color alone
   can't distinguish them; the word always does too ("Live and up to date" vs
   "You've made edits that aren't live yet"). .is-publishing is the one class
   the timer script toggles (renderTimer/finishTimer/stallTimer) so a fresh
   publish reads as "in progress," not the neutral default, before the first
   live-check tick lands. */
.pub-banner{border:1px solid var(--line);border-radius:var(--radius);padding:1.1rem 1.3rem;
  margin-bottom:1.2rem;background:var(--paper)}
.pub-banner:has(.live-dot.up){background:var(--sage-wash);border-color:transparent}
.pub-banner[data-unpub="1"]:has(.live-dot.up){background:var(--warn-wash);border-color:var(--warn-line)}
.pub-banner:has(.live-dot.building),.pub-banner.is-publishing{background:var(--warn-wash);border-color:var(--warn-line)}
.pub-banner:has(.live-dot.down){background:var(--danger-wash);border-color:var(--danger-line)}
.pub-banner[data-unpub="1"] .live-dot.up::before{content:"●"}
.pub-banner[data-unpub="1"] .live-status{color:var(--warn)}
.pub-banner:has(.live-dot.down) .live-status{color:var(--danger)}

/* Discouraged actions read as text, tinted toward caution */
.unpublish-link{color:var(--muted)}
.unpublish-link:hover{color:var(--ember)}
.unpub-line{margin-top:.9rem;margin-bottom:0}
/* The take-offline confirmation is hidden until the link is clicked. The
   [hidden] selector carries higher specificity than the base rule, so `hidden`
   always wins — never rely on an inline display that would defeat it (that bug
   left this box permanently open). */
.unpub-confirm{display:flex;gap:.6rem;flex-wrap:wrap;align-items:center;margin-top:.7rem}
.unpub-confirm[hidden]{display:none}
/* A committed legacy contact — a confirmed entry, not an editable form field */
.succ-committed{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;
  margin-bottom:.6rem;padding:.7rem .9rem;background:var(--sage-wash);border-radius:10px}
.succ-committed .succ-who{font-size:.95rem}
.succ-committed .succ-email{font-size:var(--step--1);word-break:break-all;margin-top:.05rem}
.succ-committed .succ-remove{flex:none;white-space:nowrap}

/* Locked web address, shown as text once the memorial is live */
.url-locked{display:flex;align-items:baseline;gap:.6rem;flex-wrap:wrap;margin:0;font-weight:600}
.url-locked a{color:var(--forest)}
.url-lock{font-size:var(--step--1);font-weight:400;color:var(--muted)}
.site-head{background:color-mix(in srgb,var(--cream) 88%,transparent);border-bottom:1px solid var(--line)}
.head-in{display:flex;align-items:center;gap:1rem;min-height:4.2rem;max-width:64rem;margin-inline:auto;padding:0 var(--gutter)}
.brand{display:inline-flex;align-items:center;gap:.5rem;text-decoration:none;color:var(--forest-deep);
  font-family:ui-serif,Georgia,serif;font-weight:600;font-size:1.15rem}
.brand svg{width:22px;height:26px}
/* Corp-site lockup: letterspaced caps beside the solid-cut P. */
.brand-wm{text-transform:uppercase;letter-spacing:.13em}
.head-right{margin-left:auto;display:flex;gap:1rem;align-items:center;font-size:var(--step--1)}
/* Bare header links (signed-out "Sign in") get a 44px hit area without moving:
   padding grows the target, the negative margin gives the space right back. */
.head-right>a:not(.head-dash){display:inline-flex;align-items:center;min-height:44px;
  padding:.35rem .5rem;margin:-.35rem -.5rem}
.text-size{min-width:44px;min-height:44px;border:1px solid var(--line);background:var(--paper);
  border-radius:10px;cursor:pointer;font-family:ui-serif,Georgia,serif;font-size:1.05rem;
  font-weight:600;color:var(--ink);display:inline-flex;align-items:center;justify-content:center}
.text-size:hover{border-color:var(--sage)}
main{padding:clamp(1.6rem,5vw,3rem) 0 4rem}
.mut{color:var(--muted)}
.arch-list{list-style:none;padding:0;display:flex;flex-direction:column;gap:.8rem}
/* (The old ".arch-list a" block rule is gone on purpose — it boxed every link
   inside the cards like a form input. Cards style themselves via .arch-item.) */
.pv{background:#fff;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}

/* Born/Passed pair: labels can wrap, inputs stay aligned on one baseline. */
/* Row gap matches .field's 1.15rem rhythm when the pair stacks on phones. */
.yr-row{display:grid;grid-template-columns:1fr 1fr;gap:1.15rem 1rem;align-items:end}
.yr-row label{min-height:1.5em}
@media (max-width:30rem){.yr-row{grid-template-columns:1fr}}

/* Story blocks editor */
.blk{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:1rem;margin-bottom:.9rem}
.blk-bar{display:flex;align-items:center;justify-content:space-between;margin-bottom:.6rem}
.blk-kind{font-size:var(--step--1);font-weight:600;color:var(--muted)}
.blk-btns{display:flex;gap:.4rem}
.bb{min-width:44px;min-height:44px;border:1px solid var(--line);background:#fff;border-radius:10px;
  font-size:1.05rem;cursor:pointer;color:var(--ink)}
.bb:hover{border-color:var(--sage)}
.blk img{max-height:220px;border-radius:10px;margin-bottom:.6rem}
.undo{position:fixed;left:50%;transform:translateX(-50%);bottom:1.2rem;background:var(--ink);color:#fff;
  padding:.7rem 1rem;border-radius:12px;display:flex;gap:.8rem;align-items:center;z-index:50;font-size:var(--step--1)}
.undo button{background:transparent;border:0;color:#a9c0ad;font-weight:700;cursor:pointer;font-size:inherit;min-height:44px}

/* AI assist panel (story step) */
.ai-panel{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:var(--pad-panel);margin-bottom:1.2rem}
.ai-panel > summary{cursor:pointer;font-weight:600;color:var(--forest);list-style:none;min-height:44px;display:flex;align-items:center}
.ai-panel > summary::-webkit-details-marker{display:none}
.ai-panel > summary::before{content:"✦";margin-right:.5rem;color:var(--clay)}
.ai-panel[open] > summary{margin-bottom:.4rem}

/* Publish step */
/* SW-2 (review-page-ia.md §5): the custom-domain request as its own bordered
   callout in Settings, not one more plain field in the flow — same boxed
   language as .blk, so it reads as an offer worth noticing. */
.domain-callout{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:1rem 1.1rem;margin:.9rem 0}
/* A committed domain request (has a status) is a read-only card, never an
   editable-looking form (ux-ui-practices.md) — reuses the same success/warn
   language as the publish banner so "requested/in-setup/live" reads
   consistently with every other status surface on this page. */
.domain-status{background:var(--sage-wash);border:1px solid transparent;border-radius:var(--radius);
  padding:.85rem 1rem;margin:.9rem 0;font-size:var(--step--1)}
.domain-status.pending{background:var(--warn-wash);border-color:var(--warn-line)}
.url-row{display:flex;align-items:stretch;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:#fff}
.url-row input{border:0;border-radius:0;flex:1;min-width:0}
.url-row input:focus-visible{outline:2px solid var(--forest);outline-offset:-2px}
.url-suffix{display:flex;align-items:center;padding:0 .8rem;background:var(--band-sage,var(--sage-wash));color:var(--forest);font-weight:600;white-space:nowrap;font-size:var(--step--1)}
.slug-status{margin:.4rem 0 0}

/* Header dashboard link */
.head-dash { display: inline-flex; align-items: center; gap: .3rem; color: var(--forest);
  font-weight: 600; text-decoration: none; padding: .4rem .8rem; border-radius: 999px;
  border: 1px solid var(--line); min-height: 36px; font-size: var(--step--1); }
.head-dash:hover, .head-dash:focus-visible { background: var(--sage-wash); border-color: var(--sage); }
/* Header nav: icon + label on wide screens; icon-only on phones (house and
   person are in the tiny universally-understood set — NN/g — and the
   accessible name stays via aria-label). HIG sizing: 44px targets, larger
   glyphs when the label is gone. Brand treatment identical at every size. */
.head-dash svg { width: 17px; height: 17px; }
@media (max-width: 40rem) {
  :root { --gutter: 1rem; } /* header and content share the same 16px edge */
  .head-right { gap: .5rem; }
  .head-in { gap: .6rem; }
  /* Unmissable: 48px targets (above the 44px floor), 30px glyphs — reads
     instantly as home / person even at arm's length. */
  .head-dash { padding: .55rem; min-width: 48px; min-height: 48px; justify-content: center; border-radius: 12px; }
  .head-dash .head-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .head-dash svg { width: 30px; height: 30px; stroke-width: 1.7; }
}

/* Tagline starter-idea chips */
.tagline-ideas { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .6rem; align-items: center; }
.ideas-label { font-size: var(--step--1); color: var(--muted); margin-right: .2rem; }
.idea-chip { background: var(--paper); border: 1px solid var(--line); border-radius: 999px;
  padding: .35rem .8rem; font-size: var(--step--1); color: var(--ink); cursor: pointer;
  text-align: left; line-height: 1.3; transition: background .12s ease, border-color .12s ease; }
.idea-chip:hover, .idea-chip:focus-visible { background: var(--sage-wash); border-color: var(--sage); }

/* Sticky autosave pill — always visible, incl. mobile */
/* A quiet confirmation chip — NOT a primary-colored button, and never full-width
   (it used to cover the control beneath it). Distinct color so "Saved" never
   reads as an action; compact so it stays out of the way (Garrett 2026-07-16). */
.save-pill { position: fixed; right: 1rem; bottom: 1rem; z-index: 60;
  display: inline-flex; align-items: center; gap: .3rem; max-width: min(20rem, calc(100vw - 1.6rem));
  background: var(--sage-wash); color: var(--forest); border: 1px solid var(--sage);
  padding: .4rem .8rem; border-radius: 999px; font-size: var(--step--1); font-weight: 600;
  box-shadow: 0 4px 14px rgba(43,38,32,.14); }
.save-pill[data-kind="saving"] { background: var(--cream); color: var(--muted); border-color: var(--line); }
/* An error can wrap to multiple lines — the pill (999px) radius turns that into
   a blob. A clean rounded rectangle reads as a proper message, left-aligned. */
.save-pill[data-kind="err"] { background: #fbeae7; color: var(--ember, #a1332b); border-color: #e6b3ab;
  border-radius: 10px; text-align: left; }
@media (max-width: 40rem) { .save-pill { left: auto; right: .8rem; bottom: .8rem; } }

/* Inline form messages — success vs error */
.msg { font-size: var(--step--1); padding: .55rem .85rem; border-radius: 10px; margin-top: 1rem; }
.msg:empty { display: none; }
.msg-ok { background: var(--sage-wash); color: var(--forest); border: 1px solid var(--sage); }
.msg-err { background: #fbecea; color: var(--ember, #a1332b); border: 1px solid #e5b8b2; }

/* Memories inbox */
.mem-tabs{display:flex;gap:.4rem;flex-wrap:wrap;border-bottom:1px solid var(--line);margin-bottom:.4rem}
.mem-tab{background:transparent;border:0;border-bottom:2px solid transparent;color:var(--muted);
  font:inherit;font-weight:600;font-size:var(--step--1);padding:.6rem .7rem;cursor:pointer;min-height:44px}
.mem-tab[aria-selected="true"]{color:var(--forest);border-bottom-color:var(--forest)}
.mem-count{display:inline-block;min-width:1.4em;text-align:center;background:var(--sage-wash);color:var(--forest);
  border-radius:999px;padding:0 .4em;font-size:.8em;margin-left:.25rem}
.mem-card{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--pad-panel);margin-bottom:.9rem}
.mem-head{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;margin-bottom:.5rem}
.mem-head .mut{font-size:var(--step--1)}
.mem-msg{white-space:pre-line;margin-bottom:.6rem}
.mem-photos{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:.6rem;align-items:center}
.mem-photos img{width:88px;height:88px;object-fit:cover;border-radius:10px;border:1px solid var(--line)}
.mem-audio{width:100%;max-width:24rem}
.mem-video-file{width:100%;max-width:24rem;border-radius:10px;border:1px solid var(--line)}
.mem-video{font-size:var(--step--1);margin-bottom:.6rem}
.mem-actions{display:flex;gap:.6rem;align-items:center;flex-wrap:wrap;margin-top:.7rem}
.mem-actions .btn{padding:.55rem 1rem;font-size:var(--step--1);min-height:40px}
.mem-badge{font-size:var(--step--1);font-weight:600;color:var(--muted);background:var(--cream);
  border:1px solid var(--line);border-radius:999px;padding:.25rem .7rem}
.mem-badge.ok{color:var(--forest);background:var(--sage-wash);border-color:transparent}
.mem-badge.story{color:var(--clay);background:#f3e9e3;border-color:transparent}
.mem-badge.correction{color:var(--ember);background:var(--danger-wash);border-color:transparent}
.mem-texture{list-style:none;padding:.55rem .8rem;margin:0 0 .6rem;background:var(--sage-wash);
  border-radius:10px;font-size:var(--step--1)}
.mem-texture li{margin:.15rem 0}
.mem-check{display:flex;gap:.6rem;align-items:flex-start;margin-bottom:.7rem;font-weight:400}
.mem-check input{width:auto;margin-top:.25rem}
.btn-link{background:transparent;border:0;color:var(--forest);font:inherit;font-weight:600;
  font-size:var(--step--1);cursor:pointer;text-decoration:underline;text-underline-offset:2px;
  padding:.3rem 0;min-height:40px}
.btn-link:hover{color:var(--forest-deep)}

/* Weave preview modal */
.wv-modal{position:fixed;inset:0;z-index:80;background:rgba(38,51,43,.45);
  display:flex;align-items:flex-start;justify-content:center;padding:1.2rem;overflow-y:auto}
.wv-modal[hidden]{display:none}
.wv-sheet{background:var(--paper);border-radius:var(--radius);max-width:40rem;width:100%;
  margin-block:auto;padding:1.3rem 1.4rem;box-shadow:0 18px 50px rgba(38,51,43,.3)}
.wv-sheet-head{display:flex;justify-content:space-between;align-items:center;gap:1rem;margin-bottom:.6rem}
.wv-close{background:transparent;border:0;font-size:1.2rem;color:var(--muted);cursor:pointer;min-height:40px;min-width:40px}
.wv-body{display:flex;flex-direction:column;gap:.55rem;margin:.4rem 0}
.wv{border:1px solid var(--line);border-radius:10px;padding:.7rem .85rem;background:#fff}
.wv p{font-size:var(--step--1)}
.wv-tag{display:inline-block;font-size:.75rem;font-weight:700;text-transform:uppercase;
  letter-spacing:.03em;margin-bottom:.3rem}
.wv.unchanged{opacity:.72}
.wv.unchanged .wv-tag{color:var(--muted)}
.wv.edited .wv-tag{color:var(--clay)}
.wv.new .wv-tag{color:var(--forest)}
/* Inline word-level diff — the reader sees exactly the words that changed, in
   place: added words highlighted, removed words struck. No two-paragraph re-read. */
.wv ins{background:color-mix(in srgb,var(--forest) 15%,transparent);color:var(--forest);
  text-decoration:none;border-radius:3px;padding:0 .12em;font-weight:600}
.wv del{color:var(--muted);text-decoration:line-through;text-decoration-color:var(--clay);text-decoration-thickness:1px}
.wv-before{font-size:.82rem;color:var(--muted);font-style:italic;margin-top:.3rem}
/* Inline word-diff vs stacked before/after: strikethrough inside a sentence is
   hard to read on a phone (older eyes, small type), so narrow viewports get the
   clean new sentence + a quiet "was:" line instead. Renderers emit both. */
.wv-stack{display:none}
@media (max-width: 30rem){
  .wv .wv-diff{display:none}
  .wv .wv-stack{display:block}
}
.ai-gaps{border:1px solid var(--sage);border-radius:10px;padding:.6rem .85rem;margin-top:.7rem;background:var(--sage-wash)}
.ai-gaps-lead{font-weight:600;font-size:var(--step--1);color:var(--forest)}
.ai-gaps ul{margin:.3rem 0 0;padding-left:1.1rem;font-size:var(--step--1)}

/* Story step — grouped toolbox + panels (previously unstyled) */
.story-tools-wrap{display:flex;flex-direction:column;gap:.9rem;margin:.4rem 0 1rem;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:var(--pad-panel)}
.tools-label{font-size:.78rem;font-weight:600;color:var(--muted);margin-bottom:.45rem;
  text-transform:uppercase;letter-spacing:.04em}
.story-tools{display:flex;gap:.6rem;flex-wrap:wrap}
.story-tools .btn{padding:.6rem 1.05rem;font-size:var(--step--1);min-height:44px}
/* Button grammar (consistent everywhere):
   .tool-magic  = AI writes something for you (gradient — the one "magic" accent)
   .btn-ai-ghost = secondary AI action (quiet, clay-tinted)
   .btn ghost/solid = mechanical actions and human decisions (no sparkle) */
.tool-magic{background:linear-gradient(120deg,var(--forest),var(--forest-deep))}
.btn-ai-ghost{background:transparent;color:var(--clay);box-shadow:inset 0 0 0 1.5px color-mix(in srgb,var(--clay) 40%,#fff)}
.btn-ai-ghost:hover{background:color-mix(in srgb,var(--clay) 8%,transparent);filter:none}
.tool-hint{font-size:var(--step--1);margin:.2rem 0 1rem;max-width:42rem}
.tool-hint:empty{display:none}
.import-panel{margin:0 0 1rem;padding:var(--pad-panel)}
.photos-panel{margin-bottom:1rem}
.photo-strip{display:flex;gap:.6rem;flex-wrap:wrap}
.photo-chip{position:relative;width:132px;display:flex;flex-direction:column;gap:.35rem}
/* BUILDER-16 Phase 3: an explicit display on .photo-chip ties the UA's
   [hidden]{display:none} on specificity — author wins, so `chip.hidden = true`
   silently did nothing until this rule outranks it. Found live via QA (a
   collapsed chip stayed visible even though .hidden was set correctly). */
.photo-chip[hidden]{display:none}
.photo-chip img{width:132px;height:120px;object-fit:cover;border-radius:10px;border:1px solid var(--line)}
.photo-cap{width:100%;font:inherit;font-size:var(--step--1);padding:.35rem .5rem;border:1px solid var(--line);border-radius:8px;background:var(--paper)}
.photo-cap::placeholder{color:var(--muted);opacity:.8}
.photo-x{position:absolute;top:-8px;right:-8px;width:28px;height:28px;border-radius:50%;
  border:1px solid var(--line);background:#fff;cursor:pointer;font-size:.85rem;line-height:1}
.photo-x:hover{border-color:var(--ember);color:var(--ember)}
.ai-preview{margin-top:.4rem}
/* Checkbox row inside an AI preview — the global input{width:100%} would blow it
   out, so pin the box to auto width and lay the label out beside it. */
.ai-fill-opt{display:flex;gap:.5rem;align-items:flex-start;margin:.95rem 0 .1rem;font-size:var(--step--1);cursor:pointer;line-height:1.5}
.ai-fill-opt input[type="checkbox"]{flex:none;width:auto;min-height:0;margin:.2rem 0 0}
.ai-preview-body{background:#fff;border:1px solid var(--line);border-radius:10px;
  padding:.9rem 1rem;margin-top:.7rem;max-height:24rem;overflow:auto;display:flex;flex-direction:column;gap:.7rem}
.ai-preview-body p{font-size:var(--step--1)}
.step-foot{display:flex;gap:1rem;align-items:center;justify-content:space-between;flex-wrap:wrap;margin-top:1.6rem}
.foot-preview{font-weight:600;font-size:var(--step--1)}

/* "Add a few at once" bulk entry (details step) */
.bulk-panel{margin-top:.7rem;background:var(--cream);border:1px solid var(--line);border-radius:10px;padding:.9rem 1rem}
.bulk-panel textarea{min-height:6rem;font-size:var(--step--1)}
.bulk-preview{list-style:none;padding:0;margin:.5rem 0 0;display:flex;flex-direction:column;gap:.25rem;font-size:var(--step--1)}
.bulk-preview li{background:#fff;border:1px solid var(--line);border-radius:8px;padding:.35rem .6rem}
.bulk-preview:empty{display:none}
.bulk-panel .btn{padding:.55rem 1rem;font-size:var(--step--1);min-height:40px}

/* Story orientation strip + sources cards + merge CTA */
.story-status{display:flex;gap:.4rem .5rem;flex-wrap:wrap;align-items:center;
  font-size:var(--step--1);margin:-.5rem 0 1rem}
.story-status > *:not(:first-child)::before{content:"·";margin-right:.5rem;color:var(--line)}
.story-status .btn-link{padding:.2rem 0;min-height:32px}
.src-card{border-top:1px solid var(--line);padding-top:.7rem;margin-top:.7rem}
.src-title{font-size:var(--step--1);margin-bottom:.4rem}
.src-content{white-space:pre-wrap;font-size:var(--step--1);background:var(--cream);
  border:1px solid var(--line);border-radius:8px;padding:.7rem;max-height:32rem;overflow:auto}
.src-content.clamped{max-height:9.5rem;overflow:hidden;position:relative}
.src-content.clamped::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3rem;
  background:linear-gradient(transparent,var(--cream))}
.src-more{margin-top:.3rem}
.src-merge{background:var(--sage-wash);border-radius:10px;padding:.9rem 1rem;margin-top:.8rem}

/* Voices on the memorial (story step) */
.voice-row{display:flex;gap:.8rem;align-items:flex-start;background:var(--paper);
  border:1px solid var(--line);border-radius:var(--radius);padding:.8rem 1rem;margin-bottom:.7rem}
.voice-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:.5rem}
.voice-title{font-weight:600}
.voice-main audio{width:100%;max-width:26rem}
.voice-btns{display:flex;gap:.4rem}
.bb.del:hover{border-color:var(--ember);color:var(--ember)}
@media (max-width:30rem){.voice-row{flex-direction:column}.voice-btns{align-self:flex-end}}

/* Voice recording state */
.rec-btn.rec-on{background:var(--danger-wash, #fbeae8);border-color:var(--ember);color:var(--ember);animation:rec-pulse 1.6s ease-in-out infinite}
@keyframes rec-pulse{50%{box-shadow:0 0 0 6px rgba(161,51,43,.12)}}
@media (prefers-reduced-motion: reduce){.rec-btn.rec-on{animation:none}}
/* .btn's display:inline-flex otherwise beats the bare [hidden] UA rule —
   the same footgun documented above for .unpub-confirm/.theme-modal (found
   here 2026-07-25 building the plan interview's per-card mic button). */
.rec-btn[hidden]{display:none}

/* Theme chooser */
.theme-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .6rem; margin-top: .5rem; }
.theme-card { background: var(--paper); border: 2px solid var(--line); border-radius: 12px; padding: .5rem;
  cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: .4rem; }
.theme-card[data-active="true"] { border-color: var(--forest); }
.theme-swatch { width: 100%; height: 42px; border-radius: 8px; border: 1px solid var(--line);
  display: flex; align-items: flex-end; padding: 5px; }
.theme-swatch > span { width: 40%; height: 12px; border-radius: 4px; }
.theme-name { font-size: var(--step--1); font-weight: 600; color: var(--ink); }
@media (max-width: 40rem) { .theme-grid { grid-template-columns: repeat(2, 1fr); } }

/* Inbox weave = secondary AI action (clay, per the button grammar) */
.mem-weave{color:var(--clay)}
.mem-weave:hover{color:#6e3f2a}

/* Quiet countdown, only in the last 15% of a long field */
.char-left{font-size:.78rem;color:var(--muted);align-self:center;white-space:nowrap}

/* Read-through Q&A: answer questions where they're asked */
.qa-list{margin:.4rem 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:.9rem}
.qa-item{border-top:1px solid color-mix(in srgb,var(--line) 60%,transparent);padding-top:.7rem}
.qa-issue{font-weight:600;margin-bottom:.45rem}
.qa-opts{display:flex;flex-direction:column;gap:.4rem;align-items:flex-start}
.qa-opts .btn{font-size:var(--step--1);padding:.5rem .9rem;min-height:40px;text-align:left;white-space:normal}
.qa-answer{display:flex;flex-direction:column;gap:.5rem}
.qa-answer textarea{min-height:3.2rem;font-size:var(--step--1)}
.qa-answer .btn{align-self:flex-start;font-size:var(--step--1);padding:.5rem 1rem;min-height:40px}

/* ── Rules merged from the previously-served copy (dashboard cards, skip link,
   photo strip, AI preview, etc.) — one file now, so styles can't fork again. ── */

.skip-link{position:absolute;left:.5rem;top:-3rem;z-index:100;background:var(--forest);color:#fff;
  padding:.6rem 1rem;border-radius:10px;font-weight:600;text-decoration:none;transition:top .15s ease}

.skip-link:focus{top:.5rem}

/* One cohesive card per archive: name (left) + Memories (right), one row that
   wraps on narrow screens. */
/* Interview mode toggle — one at a time (gentle default) / all at once (power path) */
.iv-mode{border:0;background:none;border-radius:999px;padding:.4rem .85rem;font:600 .8rem/1 sans-serif;color:var(--muted);cursor:pointer}
.iv-mode.on{background:var(--forest, #5d4a78);color:var(--cream, #f5f2ea)}
.iv-mode:focus-visible{outline:2px solid var(--forest, #5d4a78);outline-offset:2px}

/* Front door — the two paths, side by side (v2 mockup screen 1). Real radios;
   the card is the label. Selection reads via border + wash, works in grayscale. */
.doors{display:grid;grid-template-columns:1fr;gap:.7rem;border:0;padding:0;margin:0}
@media (min-width: 40rem){.doors{grid-template-columns:1fr 1fr}}
.door{display:flex;cursor:pointer;border:1.5px solid var(--line);border-radius:12px;background:#fff;padding:.9rem 1rem;transition:border-color .15s ease,background .15s ease}
.door input{position:absolute;opacity:0;pointer-events:none}
.door-body{display:flex;flex-direction:column;gap:.2rem;font-size:var(--step--1)}
.door-body strong{font-size:1rem;color:var(--forest)}
.door-who{font-weight:600;font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.door-desc{line-height:1.45}
/* 16px, not .74rem (11.84px). The a11y floor measured this as BODY COPY at
   390px — "Free to start · plan ahead" is six words, past the four-word label
   exemption, so it is something a person reads rather than a chip they glance
   at. CLAUDE.md: buyers "skew older, grieving". 11.84px is not a lint nit for
   that reader. BR-1's floor is 16px and it is arithmetic, not taste. */
.door-badge{align-self:flex-start;margin-top:.45rem;font-weight:600;font-size:1rem;border-radius:999px;padding:.3rem .65rem;background:var(--sage-wash);color:var(--forest)}
.door:has(input:checked){border-color:var(--forest);background:var(--sage-wash)}
.door:has(input:focus-visible){outline:2px solid var(--forest);outline-offset:2px}
.arch-item{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--pad-panel);display:flex;align-items:center;justify-content:space-between;gap:.6rem 1.5rem;flex-wrap:wrap;
  transition:border-color .12s ease}

.arch-item:hover{border-color:var(--sage)}
/* An archive that came to them through succession — carried for someone who has
   passed. A quiet distinct frame, never loud (legacy-accounts UX, 2026-07-19). */
.arch-item-care{border-color:var(--sage);box-shadow:0 0 0 1px var(--sage);background:color-mix(in srgb, var(--sage) 4%, var(--paper))}
.arch-care-badge{font:600 .72rem/1 sans-serif;letter-spacing:.04em;background:var(--sage-wash, #e7e1f2);color:var(--forest, #5d4a78);border:1px solid var(--sage);border-radius:999px;padding:.28rem .6rem;white-space:nowrap}

.arch-info{flex:1 1 16rem;min-width:0}

.arch-head-row{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap}

.arch-main{text-decoration:none;color:var(--ink);min-width:0}
.arch-main strong{font-size:1.12rem;letter-spacing:-.01em}

.arch-main:hover strong{text-decoration:underline}

.arch-status{font-size:.7rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;padding:.14rem .55rem;border-radius:999px}

.arch-status.live{background:var(--sage-wash);color:var(--forest)}

.arch-status.draft{background:var(--cream);color:var(--muted);border:1px solid var(--line)}

.arch-next{font-size:var(--step--1);margin:.25rem 0 0}

.arch-next a{color:var(--forest)}

.arch-actions{display:flex;gap:1.1rem;flex-wrap:wrap;align-items:center;font-size:var(--step--1);font-weight:600}

.arch-actions a{color:var(--forest);text-decoration:none;white-space:nowrap;display:inline-flex;align-items:center;gap:.3rem;
  border:1px solid var(--line);border-radius:10px;padding:.5rem 1rem;min-height:40px;background:transparent}

.arch-actions a:hover{border-color:var(--sage);background:var(--sage-wash)}

.arch-actions a.btn-sm{border-color:var(--forest)}

.arch-actions a.btn-sm:hover{background:var(--forest);border-color:var(--forest);filter:brightness(1.08)}

.tool-magic:hover{filter:brightness(1.06)}

.ai-preview-body p:last-child{margin-bottom:0}

.ai-gaps li{margin-bottom:.2rem}

.wv:last-child{border-bottom:0}

.foot-preview:hover{text-decoration:underline}


/* Dashboard: pending-memories badge on an archive row */
.arch-badge { display: inline-block; background: var(--clay); color: #fff; border-radius: 999px; font-size: .75rem;
  font-weight: 700; padding: .1rem .5rem; margin-left: .5rem; vertical-align: middle; }


/* Look & feel step — theme gallery + preview modal */
.wrap-wide { max-width: 60rem; }

.theme-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1.1rem; }

.theme-tile { position: relative; display: flex; flex-direction: column; }

.theme-pick { display: flex; flex-direction: column; text-align: left; padding: 0; cursor: pointer;
  background: var(--paper); border: 2px solid var(--line); border-radius: var(--radius); overflow: hidden; width: 100%; }

.theme-pick:hover { border-color: var(--sage); }

.theme-tile[data-active="true"] .theme-pick { border-color: var(--forest); box-shadow: 0 0 0 3px color-mix(in srgb, var(--forest) 20%, #fff); }

.theme-shot { display: block; aspect-ratio: 4 / 5; overflow: hidden; background: var(--cream); border-bottom: 1px solid var(--line); }

.theme-shot img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

.theme-meta { padding: .7rem .85rem .85rem; }

/* BUILDER-24 §4.1: every card-as-choice shows "chosen" in FORM as well as
   colour (WCAG 1.4.1). The theme tiles already did it with a ✓; these three
   conveyed it by colour alone. Pseudo-content so no markup or JS changes —
   `aria-pressed` already carries the state programmatically, and each of these
   keeps it in sync. */
.pm-opt.on .pm-t::before,
.photo-place.on::before,
.iv-mode.on::before { content: "✓ "; font-weight: 700; }
.theme-check { color: var(--forest); opacity: 0; font-size: .9em; }

.theme-tile[data-active="true"] .theme-check { opacity: 1; }

/* 16px, not --step--1 (13.33px measured at 390). Five theme descriptions, each
   6-10 words — the sentence that tells someone what a theme will feel like, on
   the step where they choose how their memorial looks. Body copy by any reading. */
.theme-desc { display: block; color: var(--muted); font-size: 1rem; margin-top: .15rem; line-height: 1.45; }

/* Bottom-right, not top-right. Over a memorial preview the top of the card is
   where "IN LOVING MEMORY" and the person's name sit, and on a phone the pill
   covered both. The foot of the image is background or shoulders. */
.theme-preview-btn { position: absolute; bottom: .6rem; right: .6rem; background: color-mix(in srgb, var(--ink) 78%, transparent);
  color: #fff; border: 0; border-radius: 999px; padding: .35rem .8rem; font-size: var(--step--1); font-weight: 600;
  cursor: pointer; backdrop-filter: blur(2px); min-height: 36px; }

.theme-preview-btn:hover { background: var(--ink); }


.theme-modal { position: fixed; inset: 0; z-index: 80; background: rgba(38,51,43,.55);
  display: flex; align-items: center; justify-content: center; padding: clamp(.5rem, 2vw, 1.5rem); }

.theme-modal[hidden] { display: none; }
  /* class display:flex would otherwise beat [hidden] */
.theme-modal-in { background: var(--cream); border-radius: var(--radius); width: min(72rem, 100%); height: min(90vh, 100%);
  display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 20px 60px rgba(38,51,43,.4); }

.theme-modal-bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .8rem 1rem; border-bottom: 1px solid var(--line); flex-wrap: wrap; }

.theme-modal-note { margin: 0; padding: .5rem 1rem 0; }

.theme-modal-frame { flex: 1; min-height: 0; padding: .6rem 1rem 1rem; }

.theme-modal-frame iframe { width: 100%; height: 100%; border: 1px solid var(--line); border-radius: 10px; background: #fff; }

/* Wishes: radio CARDS that wrap on any width (the inline version broke on
   phones). Radio + body, body wraps, selection reads as a filled card. */
.wish-style{display:flex;gap:.7rem;align-items:flex-start;border:1px solid var(--line);border-radius:12px;
  padding:.8rem 1rem;cursor:pointer;background:var(--paper)}
/* The global input{width:100%} rule hits RADIOS too — the little circle's
   layout box swallowed the whole row and squeezed the text to width 0
   (found by computed-style probe: bodyW=0, x beyond the card). */
.wish-style input{margin-top:.3rem;flex:none;width:auto}
.wish-style .ws-body{display:block;min-width:0}
.wish-style .ws-body b{display:block}
.wish-style .ws-body .mut{font-size:var(--step--1)}
.wish-style.on{border-color:var(--forest);background:var(--sage-wash)}

/* Dashboard hierarchy: ONE primary action per card; the rest are quiet links. */
.arch-actions .btn-sm{background:var(--forest);color:#fff;border-radius:10px;padding:.5rem 1rem;min-height:40px;
  display:inline-flex;align-items:center;font-weight:600;text-decoration:none}
.arch-actions .btn-sm:hover{filter:brightness(1.08);text-decoration:none}

/* Current-page state for header nav: filled pill, consistent icons that never
   disappear — position is shown, not implied by absence. */
.head-dash.head-on{background:var(--sage-wash);border-color:transparent;color:var(--forest-deep)}

.wish-fold > summary{list-style:none}
.wish-fold > summary::-webkit-details-marker{display:none}
.wish-fold > summary::after{content:"▾";float:right;color:var(--muted);transition:transform .15s}
.wish-fold[open] > summary::after{transform:rotate(180deg)}

/* Photo placement segmented toggle: quiet two-state, the ON side filled. */
.photo-place{flex:1;font:inherit;font-size:.72rem;font-weight:600;padding:.28rem .3rem;border:1px solid var(--line);
  background:var(--paper);color:var(--muted);cursor:pointer}
.photo-place:first-of-type{border-radius:8px 0 0 8px}
.photo-place:last-of-type{border-radius:0 8px 8px 0;border-left:0}
.photo-place.on{background:var(--sage-wash);color:var(--forest);border-color:var(--sage)}

/* Photo placement: the up-front woven-vs-gallery choice + numbering + budget */
.photo-mode{display:grid;grid-template-columns:1fr 1fr;gap:.6rem;margin-bottom:.8rem}
.pm-opt{text-align:left;border:1.5px solid var(--line);background:var(--paper);border-radius:12px;
  padding:.7rem .85rem;cursor:pointer;display:flex;flex-direction:column;gap:.15rem;font:inherit}
.pm-opt .pm-t{font-weight:600;font-size:.92rem;color:var(--ink)}
.pm-opt .pm-d{font-size:var(--step--1);color:var(--muted)}
.pm-opt.on{border-color:var(--forest);box-shadow:0 0 0 3px color-mix(in srgb,var(--forest) 13%,transparent)}
.pm-opt:hover{border-color:var(--sage)}
.photo-budget{display:flex;align-items:center;gap:.5rem .7rem;flex-wrap:wrap;background:var(--sage-wash);
  border-radius:10px;padding:.55rem .8rem;margin-bottom:.85rem;font-size:var(--step--1);color:var(--ink)}
.photo-budget b{font-weight:700}
.photo-budget .btn-link{margin-left:auto;white-space:nowrap}
.photo-num{position:absolute;top:.35rem;left:.35rem;z-index:2;background:var(--forest);color:#fff;
  font-size:.72rem;font-weight:700;min-width:1.3rem;height:1.3rem;border-radius:7px;display:grid;
  place-items:center;padding:0 .32rem;box-shadow:0 1px 3px rgba(0,0,0,.28)}
.photo-cat{position:absolute;top:.35rem;right:.35rem;z-index:2;background:rgba(255,255,255,.94);
  border:1px solid var(--line);border-radius:7px;font-size:.85rem;line-height:1.3;padding:.02rem .28rem;box-shadow:0 1px 3px rgba(0,0,0,.15)}
@media(max-width:30rem){.photo-mode{grid-template-columns:1fr}}

/* Visual arrange view: the story as it reads, photos between the paragraphs */
.arrange{border:1px solid var(--line);border-radius:14px;background:var(--paper);padding:.4rem clamp(.6rem,3vw,1.4rem) 1rem;margin-bottom:1rem}
.arr-para{font-family:Georgia,'Iowan Old Style',serif;font-size:1rem;line-height:1.7;color:#38312a;margin:.2rem 0;padding:.2rem 0}
.arr-gap{display:flex;flex-direction:column;gap:.5rem;margin:.25rem 0;align-items:stretch}
/* The between-paragraphs "place a photo" affordance — the primary way to weave a
   photo into the story, so it earns a clearer, more tappable presence (was small
   and easy to miss). Still quiet until hovered/focused. */
.arr-slot{align-self:center;display:inline-flex;align-items:center;min-height:40px;border:1px dashed var(--line);
  background:var(--cream);color:var(--muted);border-radius:999px;padding:.45rem 1.15rem;font:inherit;font-size:.85rem;
  font-weight:500;cursor:pointer;opacity:.9;transition:opacity .12s,border-color .12s,background .12s}
.arr-slot:hover,.arr-slot:focus-visible{opacity:1;border-color:var(--sage);color:var(--forest);background:var(--sage-wash)}
.arr-gap.has .arr-slot{opacity:.5}
.arr-photo{margin:0;position:relative;border-radius:12px;overflow:hidden;border:1px solid var(--line);background:#fcf8ef}
/* contain, not cover: the arrange view is a PREVIEW of the page, and the page
   shows the whole photo (see .inline-photo on the site — no crop). cover here
   hid the top/sides of tall photos and made people think the page would crop
   them too (Garrett, 2026-07-20). contain scales the whole photo to fit the
   space cap instead; the cream mat fills any letterbox, so a portrait reads as
   framed — which is exactly how the published memorial mats it. */
.arr-photo img{display:block;width:100%;height:auto;max-height:22rem;object-fit:contain}
.arr-ctl{position:absolute;top:.5rem;right:.5rem;display:flex;gap:.4rem}
/* 44px touch targets (was 32) — the overlay move/remove controls were small and
   easy to miss on a phone (Garrett, 2026-07-20). */
.arr-ctl button{width:2.75rem;height:2.75rem;border-radius:10px;border:0;background:rgba(35,30,24,.62);color:#fff;cursor:pointer;
  font-size:1.2rem;line-height:1;display:grid;place-items:center;backdrop-filter:blur(2px)}
.arr-ctl button:hover{background:rgba(35,30,24,.82)}
.arr-ctl button:disabled{opacity:.35;cursor:default}
.arr-pick{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;padding:.6rem;background:var(--sage-wash);border-radius:10px}
.arr-pick-p{padding:0;border:2px solid transparent;border-radius:9px;background:none;cursor:pointer;line-height:0}
.arr-pick-p img{width:60px;height:60px;object-fit:cover;border-radius:8px;border:1px solid var(--line)}
.arr-pick-p:hover img,.arr-pick-p:focus-visible img{border-color:var(--forest)}

/* Dashboard hub rows — quiet, informative, brand-toned. */
.arch-rows{width:100%;border-top:1px solid var(--line);margin-top:.85rem;padding-top:.7rem;display:flex;flex-direction:column;gap:.35rem}
.arch-row{margin:0;font-size:var(--step--1);color:var(--muted)}
.arch-row a{color:var(--forest)}
.arch-row-k{display:inline-block;font-size:.68rem;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--forest);margin-right:.5rem;opacity:.9}
.linklike{background:none;border:0;padding:0;font:inherit;color:var(--forest);text-decoration:underline;cursor:pointer}
.copy-ok{color:var(--forest);font-weight:600;margin-left:.35rem}
.arch-item-helping{background:var(--cream)}

/* Family invite rows — email + status on the left, quiet retract on the right. */
.inv-row{display:flex;justify-content:space-between;align-items:baseline;gap:.6rem 1rem;flex-wrap:wrap;font-size:var(--step--1);padding:.35rem 0;border-bottom:1px solid var(--line)}
.inv-row:last-child{border-bottom:0}
.inv-who{display:flex;gap:.5rem;align-items:baseline;flex-wrap:wrap;min-width:0}
.inv-del{background:none;border:0;padding:.15rem .35rem;font:inherit;font-size:var(--step--1);color:var(--clay);cursor:pointer;text-decoration:underline;white-space:nowrap}
.inv-del:hover{color:#8a2b2b}
.inv-del:disabled{opacity:.5;cursor:default}

/* Dashboard "For you" region — surfaces pre-need planning as a first-class,
   discoverable offering (not a buried link). */
.foryou{margin:0 0 2rem}
.foryou-links{display:grid;gap:.7rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.foryou-card{display:flex;flex-direction:column;gap:.25rem;padding:.9rem 1.1rem;border:1px solid var(--line);
  border-radius:var(--radius);background:var(--paper);text-decoration:none;color:var(--ink);transition:border-color .12s ease,background .12s ease}
.foryou-card:hover{border-color:var(--sage);background:var(--sage-wash)}
.foryou-card strong{color:var(--forest)}
.foryou-card .mut{font-size:var(--step--1)}

.people-list{list-style:none;padding:0;margin:0}

/* ── Mobile tap-target floor (Garrett 2026-07: "honest tap targets"). Desktop
   keeps its quieter density; on phone widths every button-shaped control meets
   the 44px floor. Inline-in-prose links (.linklike) are exempt per WCAG 2.5.8's
   inline exception; .photo-x / .photo-place are reported, not resized, because
   44px would break their compact compositions. ── */
@media (max-width:40rem){
  .chip,.idea-chip,.btn-link,.mem-actions .btn,.bulk-panel .btn,
  .qa-opts .btn,.qa-answer .btn,.arch-actions a,.arch-actions .btn-sm,
  .theme-preview-btn,.wv-close,.story-status .btn-link,.arr-slot{min-height:44px}
  .wv-close{min-width:44px}
  .arr-ctl button{width:2.75rem;height:2.75rem}
}

/* BUILDER-25 D4 — "Shown in" on a woven memory. Quiet by design: it is a
   statement of fact the owner may want to act on, not an alert. Values read as
   plain chips so "the story · the tributes" is scannable at a glance. */
.mem-shown{display:flex;flex-wrap:wrap;gap:.4rem .55rem;align-items:center;margin:.6rem 0 0;
  font-size:var(--step--1);color:var(--muted)}
.mem-shown-k{font-weight:600;color:var(--ink)}
.mem-shown-v{background:var(--sage-wash);color:var(--forest);border-radius:999px;padding:2px 10px;font-weight:600}
.mem-shown-off{background:var(--cream);border:1px solid var(--line);border-radius:999px;padding:2px 10px}

/* BUILDER-23 1a — textareas that grow with their content instead of becoming a
   nested scroll region. A box that scrolls inside a page that also scrolls hides
   whatever sits below it, and on a phone the thumb lands in the wrong one. */
textarea.autogrow{overflow-y:hidden;resize:none;field-sizing:content}

/* BUILDER-23 1b — ONE AI grammar. Exactly two presentations exist:
   • panel action  — the ✨ button inside a "want a hand?" panel; starts something
   • inline assist — .assist, a quiet chip beside the content it acts on
   Nothing else. The story step had three dialects (dark button, ghost button,
   underlined sparkle link) for jobs at the same altitude, so the AI read as
   scattered rather than as one helper. Ghost-button padding, chip shape, and it
   never competes with the primary action on the screen. */
.assist{display:inline-flex;align-items:center;gap:.35rem;min-height:38px;
  padding:.4rem .9rem;border-radius:999px;border:1.5px solid var(--line);
  background:var(--paper);color:var(--forest);font:inherit;font-size:var(--step--1);
  font-weight:600;cursor:pointer;text-decoration:none}
.assist:hover,.assist:focus-visible{border-color:var(--sage);background:var(--sage-wash)}
.assist:disabled{opacity:.6;cursor:default}
/* `display:inline-flex` above beats the UA stylesheet's [hidden]{display:none},
   so an assist told to hide stayed visible — caught by looking at the render,
   not by reading the code. Any component that sets `display` must restate this. */
.assist[hidden]{display:none}
