/* Account Sniffer components. Version: design/VERSION. Load after tokens.css.
   Class prefix as-. Colors, type, space and shape come only from tokens,
   so light and dark both work. Each block names the screens that use it. */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

.as-body {
  margin: 0;
  background: var(--as-bg);
  color: var(--as-text);
  font-family: var(--as-font-body);
  font-size: var(--as-size-body);
  line-height: var(--as-lh-body);
  -webkit-font-smoothing: antialiased;
}
.as-body h1:focus { outline: none; } /* route changes move focus to the h1 */

/* ---------- Type ---------- */
.as-h1, .as-h2, .as-h3 { font-family: var(--as-font-display); font-weight: 400; margin: 0; text-wrap: balance; }
.as-h1 { font-size: var(--as-size-h1); line-height: var(--as-lh-tight); }
.as-h2 { font-size: var(--as-size-h2); line-height: 1.25; }
.as-h3 { font-size: var(--as-size-h3); line-height: var(--as-lh-snug); }
.as-h4 { font-family: var(--as-font-body); font-size: var(--as-size-h4); font-weight: 600; line-height: var(--as-lh-snug); margin: 0; }
.as-lede { font-size: var(--as-size-body-lg); color: var(--as-text-muted); max-width: var(--as-measure); margin: 0; }
.as-p { max-width: var(--as-measure); margin: 0; }
.as-small { font-size: var(--as-size-small); }
.as-label { font-size: var(--as-size-label); font-weight: 500; line-height: 1.4; }
.as-caption { font-size: var(--as-size-caption); color: var(--as-text-muted); line-height: 1.45; }
.as-eyebrow { font-size: var(--as-size-caption); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--as-text-muted); }
.as-muted { color: var(--as-text-muted); }
.as-num { font-variant-numeric: tabular-nums; }
.as-link { color: var(--as-text-accent); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.as-link:hover { text-decoration-thickness: 2px; }
.as-sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Focus: one ring everywhere */
:where(.as-btn, .as-choice input, .as-input, .as-check input, .as-todo__tick input, .as-file input, .as-stepbar__btn, .as-link, .as-tab, .as-seg input, .as-theme, .as-pill, .as-breed input, a.as-inv-row, .as-steps__link, .as-more > summary, .as-disclose, a.as-resume__next):focus-visible {
  outline: none; box-shadow: var(--as-focus-ring);
}

/* ---------- Brand pieces ---------- */
/* Scent trail: three dots that grow. Decorative; never inside text or controls. */
.as-trail { display: inline-flex; gap: 6px; align-items: center; }
.as-trail i { display: block; border-radius: 50%; background: var(--as-scent); }
.as-trail i:nth-child(1) { width: 6px; height: 6px; }
.as-trail i:nth-child(2) { width: 8px; height: 8px; }
.as-trail i:nth-child(3) { width: 10px; height: 10px; }

/* Logo: Kash, the default sniffer, plus the name. The same on light and dark grounds.
   Inline design/art/logo.svg once and draw it with <use href="#as-logo"/>. */
.as-logo { display: inline-flex; align-items: center; gap: var(--as-space-2); color: var(--as-logo-ink); text-decoration: none; font: 400 1.2rem/1 var(--as-font-display); }
.as-logo svg { width: 36px; height: 36px; flex: none; }

/* Name tag chip: the sniffer's name on its tag. Start, header, tips. */
.as-tagchip { display: inline-flex; align-items: center; gap: var(--as-space-2); background: var(--as-tag); color: var(--as-on-tag); border-radius: var(--as-radius-tag); padding: 4px 14px 4px 4px; font: 600 .9rem/1.2 var(--as-font-body); }

/* Dog avatar: round badge holding the sniffer's face. Sizes: sm 28, md 56, lg 72. */
.as-avatar { display: inline-block; flex: none; width: 28px; height: 28px; border-radius: 50%; overflow: hidden; background: var(--as-avatar-bg); }
.as-avatar > svg { display: block; width: 100%; height: 100%; }
.as-avatar--md { width: 56px; height: 56px; }
.as-avatar--lg { width: 72px; height: 72px; }
.as-tagchip .as-avatar { width: 30px; height: 30px; }

/* Dog art: the animated sniffer (design/art/<breed>-<moment>.svg). */
.as-art { display: block; width: min(220px, 60%); height: auto; aspect-ratio: 1 / 1; max-width: 100%; background: var(--as-art-bg); border-radius: 22%; }
.as-art { overflow: hidden; }
.as-art > svg { display: block; width: 100%; height: 100%; }

/* Hero scene: the start screen's sniffer, on a glowing panel with floating papers,
   rising scent dots and the sniffer's name on a swinging tag. */
.as-scene { position: relative; aspect-ratio: 1 / 1; width: min(300px, 82%); max-width: 100%; border-radius: var(--as-radius-xl); overflow: hidden; isolation: isolate; background: radial-gradient(120% 90% at 50% 20%, var(--as-scene-a) 0%, var(--as-scene-b) 100%); }
.as-scene__bg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; }
.as-scene .as-art { position: absolute; left: 12%; bottom: 4%; width: 76%; background: transparent; border-radius: 0; z-index: 1; }
.as-scene__glow { fill: var(--as-scent); transform-box: fill-box; transform-origin: center; animation: as-scene-glow 5s ease-in-out infinite; }
.as-scene__glow2 { fill: var(--as-scent); opacity: .18; transform-box: fill-box; transform-origin: center; animation: as-scene-glow 5s ease-in-out infinite reverse; }
.as-scene__ring { fill: none; stroke: var(--as-scene-ring); stroke-opacity: .35; stroke-width: 2; stroke-dasharray: 3 10; stroke-linecap: round; transform-origin: 200px 215px; animation: as-scene-spin 80s linear infinite; }
.as-scene__paper .pg { fill: var(--as-scene-paper); }
.as-scene__paper .ln { fill: var(--as-scene-line); }
.as-scene__paper .hl { fill: var(--as-scent); }
.as-scene__paper { transform-box: fill-box; transform-origin: center; animation: as-scene-float 6s ease-in-out infinite; }
.as-scene__paper.p2 { animation-duration: 7.5s; animation-delay: -2s; }
.as-scene__paper.p3 { animation-duration: 6.8s; animation-delay: -4s; }
.as-scene__dot { fill: var(--as-scent); animation: as-scene-rise 4.5s ease-in infinite; opacity: 0; }
.as-scene__dot.d2 { animation-delay: -1.5s; }
.as-scene__dot.d3 { animation-delay: -3s; }
.as-scene__tag { position: absolute; right: 7%; top: 8%; z-index: 2; display: inline-flex; align-items: center; gap: 6px; background: var(--as-tag); color: var(--as-on-tag); font: 700 .85rem/1 var(--as-font-body); padding: 7px 12px 7px 9px; border-radius: var(--as-radius-pill); box-shadow: var(--as-shadow-tag); transform-origin: 50% -14px; animation: as-scene-swing 3.6s ease-in-out infinite; }
.as-scene__tag::before { content: ""; width: 9px; height: 9px; border-radius: 50%; background: var(--as-on-tag); opacity: .85; }
@keyframes as-scene-glow { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }
@keyframes as-scene-spin { to { transform: rotate(360deg); } }
@keyframes as-scene-float { 0%, 100% { transform: translateY(0) rotate(0); } 50% { transform: translateY(-10px) rotate(3deg); } }
@keyframes as-scene-rise { 0% { opacity: 0; transform: translateY(0); } 20% { opacity: .9; } 100% { opacity: 0; transform: translateY(-70px); } }
@keyframes as-scene-swing { 0%, 100% { transform: rotate(-5deg); } 50% { transform: rotate(5deg); } }
@media (prefers-reduced-motion: reduce) {
  .as-scene__glow, .as-scene__glow2, .as-scene__ring, .as-scene__paper, .as-scene__tag { animation: none; }
  .as-scene__dot { animation: none; opacity: .7; }
}

/* ---------- Buttons ---------- */
.as-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--as-space-2);
  min-height: var(--as-target); padding: 0 var(--as-space-5);
  font: 500 var(--as-size-small)/1 var(--as-font-body);
  border-radius: var(--as-radius); border: var(--as-border-control) solid var(--as-primary);
  background: var(--as-primary); color: var(--as-on-primary);
  cursor: pointer; text-decoration: none;
  transition: background var(--as-dur-fast) var(--as-ease), border-color var(--as-dur-fast) var(--as-ease), transform var(--as-dur-fast) var(--as-ease-spring), opacity var(--as-dur) var(--as-ease);
}
.as-btn:hover { background: var(--as-primary-hover); border-color: var(--as-primary-hover); }
.as-btn--secondary { background: transparent; color: var(--as-text); border-color: var(--as-line-strong); }
.as-btn--secondary:hover { background: var(--as-selected-bg); border-color: var(--as-text); }
.as-btn--quiet { background: transparent; color: var(--as-text); border-color: transparent; text-decoration: underline; text-underline-offset: 3px; padding: 0 var(--as-space-3); }
.as-btn--quiet:hover { background: var(--as-surface-sunk); border-color: transparent; }
.as-btn--block { width: 100%; }
.as-btn--lg { min-height: var(--as-target-lg); font-size: var(--as-size-body); }
.as-btn .as-icon { width: 20px; height: 20px; }
.as-btn:is([disabled], [aria-disabled="true"]) { opacity: .45; cursor: not-allowed; }
.as-btn:is([disabled], [aria-disabled="true"]):hover { background: var(--as-primary); border-color: var(--as-primary); }
.as-btn--secondary:is([disabled], [aria-disabled="true"]):hover { background: transparent; border-color: var(--as-line-strong); }
.as-btn--quiet:is([disabled], [aria-disabled="true"]):hover { background: transparent; border-color: transparent; }
a.as-btn { color: var(--as-on-primary); }
a.as-btn--secondary, a.as-btn--quiet { color: var(--as-text); }

/* Pill toggles: small on/off choices (contact method). */
.as-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.as-pill { font: 600 var(--as-size-label)/1 var(--as-font-body); min-height: var(--as-target); padding: 0 14px; border-radius: var(--as-radius-pill); border: var(--as-border-control) solid var(--as-line); background: transparent; color: var(--as-text); cursor: pointer; transition: transform var(--as-dur-fast) var(--as-ease-spring); }
.as-pill[aria-pressed="true"] { background: var(--as-primary); color: var(--as-on-primary); border-color: var(--as-primary); }

/* Theme toggle in the app bar. */
.as-theme { display: inline-grid; place-items: center; width: var(--as-target); height: var(--as-target); border-radius: var(--as-radius-pill); border: var(--as-border-control) solid var(--as-line); background: transparent; color: var(--as-text); cursor: pointer; transition: transform var(--as-dur-fast) var(--as-ease-spring); }
.as-theme:hover { background: var(--as-surface-sunk); }

/* ---------- Icons ---------- */
/* 24px grid, 1.75 stroke, round caps and joins, currentColor. */
.as-icon { width: 24px; height: 24px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }

/* ---------- Surfaces ---------- */
.as-card { background: var(--as-surface); border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius-lg); padding: var(--as-space-5); display: grid; gap: var(--as-space-3); }
.as-card--strong { border-color: var(--as-line-strong); }
.as-card--offer { border: 2px solid var(--as-scent); } /* Document Sniff offer only */
.as-inverse { background: var(--as-surface-inverse); color: var(--as-text-inverse); border-color: transparent; }

/* Sniffer tip: the dog speaks, on a soft lilac panel. */
.as-tip { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: var(--as-space-3); align-items: start; background: var(--as-surface-soft); border-radius: var(--as-radius); padding: var(--as-space-3) var(--as-space-4); font-size: var(--as-size-small); }
.as-tip strong { display: block; font-family: var(--as-font-display); font-weight: 400; font-size: 1.05rem; margin-bottom: 2px; }

/* Callouts: info, trust (privacy promises), found, blocked. */
.as-callout { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--as-space-3); padding: var(--as-space-4) var(--as-space-5); border-radius: var(--as-radius); font-size: var(--as-size-small); line-height: 1.5; color: var(--as-text); }
.as-callout > .as-icon { width: 22px; height: 22px; margin-top: 1px; }
.as-callout p { margin: 0; }
.as-callout strong { display: block; font-weight: 600; }
.as-callout--info { background: var(--as-info-bg); }
.as-callout--info > .as-icon { color: var(--as-text-accent); }
.as-callout--trust { background: var(--as-selected-bg); }
.as-callout--found { background: var(--as-found-bg); }
.as-callout--found > .as-icon { color: var(--as-found); }
.as-callout--blocked { background: var(--as-blocked-bg); }
.as-callout--blocked > .as-icon { color: var(--as-blocked); }
.as-callout--waiting { background: var(--as-waiting-bg); }
.as-callout--waiting > .as-icon { color: var(--as-waiting); }

/* Our promise (AS-42): what we never ask for and never do, said up front on
   the start and lane pages. The one high-contrast block on those pages. */
.as-pledge { display: grid; gap: var(--as-space-4); background: var(--as-surface-inverse); color: var(--as-text-inverse); border-radius: var(--as-radius-lg); padding: var(--as-space-5); }
.as-pledge__head { display: grid; grid-template-columns: 48px minmax(0, 1fr); gap: var(--as-space-3); align-items: center; }
.as-pledge__seal { display: grid; place-items: center; width: 48px; height: 48px; border-radius: var(--as-radius-pill); background: var(--as-tag); color: var(--as-on-tag); }
.as-pledge__seal .as-icon { width: 26px; height: 26px; }
.as-pledge__title { margin: 0; font-family: var(--as-font-display); font-weight: 400; font-size: var(--as-size-h3); line-height: var(--as-lh-snug); }
.as-pledge__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-3); }
.as-pledge__list li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--as-space-3); font-size: var(--as-size-small); line-height: 1.5; }
.as-pledge__list .as-icon { box-sizing: border-box; width: 24px; height: 24px; padding: 4px; border-radius: var(--as-radius-pill); background: var(--as-tag); color: var(--as-on-tag); }
@media (min-width: 768px) {
  .as-pledge { padding: var(--as-space-6); }
  .as-pledge__list { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--as-space-6); }
}

/* The promise, in one line: a quiet reminder where people type, and at the
   foot of every page (.as-foot). Never a box, never something to dismiss. */
.as-reassure { display: flex; align-items: flex-start; gap: var(--as-space-2); margin: 0; font-size: var(--as-size-label); line-height: 1.45; color: var(--as-text-muted); }
.as-reassure .as-icon { flex: none; width: 18px; height: 18px; margin-top: 1px; color: var(--as-text-accent); }
.as-foot { max-width: var(--as-wide); margin-inline: auto; padding-block: 0 calc(var(--as-space-6) + env(safe-area-inset-bottom, 0px)); padding-inline: max(var(--as-space-4), env(safe-area-inset-left, 0px)) max(var(--as-space-4), env(safe-area-inset-right, 0px)); display: grid; justify-items: center; }
.as-foot .as-reassure { max-width: 44ch; }
/* The links to the privacy policy, terms and refund policy, under the promise. */
.as-foot { row-gap: var(--as-space-2); }
.as-foot__nav { display: flex; flex-wrap: wrap; justify-content: center; column-gap: var(--as-space-5); font-size: var(--as-size-label); }
.as-foot__nav .as-link { min-height: var(--as-target); display: inline-flex; align-items: center; color: var(--as-text-muted); }
.as-foot__nav .as-link:hover { color: var(--as-text); }

/* A plain bulleted list in running text, like the legal pages. */
.as-list { margin: 0; padding-left: var(--as-space-5); max-width: var(--as-measure); display: grid; gap: var(--as-space-2); }
.as-list li { padding-left: var(--as-space-1); }
.as-list li::marker { color: var(--as-text-accent); }

/* Sample badge: required wherever guide text is a placeholder. */
.as-badge { display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border: 1.5px dashed var(--as-text-accent); border-radius: var(--as-radius-pill); color: var(--as-text-accent); font-size: var(--as-size-label); font-weight: 600; line-height: 1.5; white-space: nowrap; }
.as-badge .as-icon { width: 16px; height: 16px; }

/* ---------- Questions ---------- */
.as-choices { display: grid; gap: var(--as-space-3); border: 0; padding: 0; margin: 0; min-width: 0; }
.as-choices legend { font-family: var(--as-font-display); font-size: var(--as-size-h2); line-height: 1.25; margin-bottom: var(--as-space-4); padding: 0; }
.as-choice {
  position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px var(--as-space-4); align-items: start;
  min-height: 64px; padding: var(--as-space-4) var(--as-space-5);
  background: var(--as-surface); border: var(--as-border-control) solid var(--as-line-strong); border-radius: var(--as-radius);
  cursor: pointer; transition: border-color var(--as-dur-fast) var(--as-ease), background var(--as-dur-fast) var(--as-ease), transform var(--as-dur-fast) var(--as-ease-spring);
}
.as-choice:hover { border-color: var(--as-text); }
.as-choice input { appearance: none; margin: 4px 0 0; width: 22px; height: 22px; border: 2px solid var(--as-line-strong); border-radius: 50%; grid-row: span 2; background: var(--as-surface); display: grid; place-content: center; transition: border-color var(--as-dur-fast) var(--as-ease), background var(--as-dur-fast) var(--as-ease); }
.as-choice input::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--as-primary); transform: scale(0); transition: transform var(--as-dur) var(--as-ease-pop); }
.as-choice input:checked { border-color: var(--as-primary); }
.as-choice input:checked::after { transform: scale(1); }
.as-choice input[type="checkbox"] { border-radius: 6px; }
.as-choice input[type="checkbox"]::after { width: 11px; height: 6px; border-radius: 0; background: transparent; border-left: 2.5px solid var(--as-on-primary); border-bottom: 2.5px solid var(--as-on-primary); margin-top: -3px; transform: rotate(-45deg) scale(0); }
.as-choice input[type="checkbox"]:checked { background: var(--as-primary); }
.as-choice input[type="checkbox"]:checked::after { transform: rotate(-45deg) scale(1); }
.as-choice:has(input:checked) { border-color: var(--as-primary); background: var(--as-selected-bg); }
.as-choice__title { font-weight: 600; font-size: var(--as-size-body); line-height: 1.35; }
.as-choice__hint { font-size: var(--as-size-small); color: var(--as-text-muted); line-height: 1.45; }
.as-choice--icon { grid-template-columns: auto 40px minmax(0, 1fr); align-items: center; }
.as-choice--icon input { margin-top: 0; }
.as-choice__icon { grid-row: span 2; width: 40px; height: 40px; border-radius: var(--as-radius-sm); background: var(--as-selected-bg); color: var(--as-text); display: grid; place-items: center; }
.as-choice:has(input:checked) .as-choice__icon { background: var(--as-surface); }

/* Start question: a lane page's first question, right in the hero. Each
   answer is a button, so one tap answers it and opens Step 1. */
.as-startq { display: grid; gap: var(--as-space-3); min-width: 0; background: var(--as-surface); border: var(--as-border) solid var(--as-line-strong); border-radius: var(--as-radius-lg); padding: var(--as-space-5); }
.as-startq__q { margin: 0; font-family: var(--as-font-display); font-weight: 400; font-size: var(--as-size-h3); line-height: var(--as-lh-snug); }
.as-startq__hint { margin: 0; font-size: var(--as-size-small); color: var(--as-text-muted); line-height: 1.5; }
/* Its answers are the same choices as the questions, a little tighter: picking
   one only picks it, and the button under them opens Step 1 (1.21.0). */
.as-startq .as-choices { gap: var(--as-space-2); }
.as-startq .as-choice { min-height: 56px; padding: var(--as-space-3) var(--as-space-4); gap: 2px var(--as-space-3); }
.as-startq__note { margin: 0; font-size: var(--as-size-label); color: var(--as-text-muted); }

/* Breed picker: three dogs side by side, even on a phone. */
.as-breeds { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; border: 0; padding: 0; margin: 0; min-width: 0; }
.as-breed { position: relative; display: grid; justify-items: center; gap: 4px; text-align: center; border: var(--as-border-control) solid var(--as-line); border-radius: var(--as-radius); padding: 10px 6px; cursor: pointer; background: var(--as-surface); transition: border-color var(--as-dur-fast) var(--as-ease), box-shadow var(--as-dur-fast) var(--as-ease), transform var(--as-dur-fast) var(--as-ease-spring); }
.as-breed input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; border-radius: inherit; }
.as-breed b { font-size: var(--as-size-small); }
.as-breed small { font-size: var(--as-size-label); color: var(--as-text-muted); line-height: 1.3; }
.as-breed .as-avatar { width: 72px; height: 72px; }
.as-breed:has(input:checked) { border-color: var(--as-primary); box-shadow: 0 0 0 2px var(--as-tag); }

/* Progress bar with "Question 3 of 8". */
.as-progress { display: grid; gap: var(--as-space-2); }
.as-progress__bar { height: 6px; border-radius: var(--as-radius-pill); background: var(--as-surface-sunk); overflow: hidden; }
.as-progress__fill { height: 100%; background: var(--as-primary); border-radius: inherit; transition: width var(--as-dur-slow) var(--as-ease); }
.as-progress__meta { display: flex; justify-content: space-between; gap: var(--as-space-3); font-size: var(--as-size-label); color: var(--as-text-muted); font-variant-numeric: tabular-nums; }

/* Answer recap pills under the guide title. */
.as-answers { display: flex; flex-wrap: wrap; gap: var(--as-space-2); }
.as-answers span { font-size: var(--as-size-label); padding: 4px 10px; border-radius: var(--as-radius-pill); background: var(--as-surface-sunk); }

/* ---------- Guide ---------- */
/* Numbered "four places to look" list. */
.as-four { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.as-four li { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: var(--as-space-3); align-items: start; }
.as-four .as-four__n { width: 34px; height: 34px; border-radius: 50%; background: var(--as-tag); color: var(--as-on-tag); display: grid; place-items: center; font: 400 1.05rem/1 var(--as-font-display); }
.as-four span { display: grid; gap: 2px; }
.as-four small { color: var(--as-text-muted); font-size: var(--as-size-small); }

/* Stepper: guide overview. Rows are buttons that open a step in place. */
.as-steps { list-style: none; margin: 0; padding: 0; display: grid; }
.as-steps li { position: relative; padding-block: var(--as-space-1); }
.as-steps li::before { content: ""; position: absolute; left: 15px; top: 44px; bottom: -4px; width: 2px; background: var(--as-line); }
.as-steps li:last-child::before { display: none; }
.as-steps__link { display: grid; grid-template-columns: 32px minmax(0, 1fr); gap: var(--as-space-3); align-items: start; width: calc(100% + 2 * var(--as-space-2)); min-height: var(--as-target); padding: var(--as-space-1) var(--as-space-2); margin-inline: calc(-1 * var(--as-space-2)); border: 0; border-radius: var(--as-radius-sm); background: none; color: inherit; font: inherit; text-align: left; text-decoration: none; cursor: pointer; }
.as-steps__link[aria-current="step"] { background: var(--as-selected-bg); }
.as-steps__link:hover .as-step-title { text-decoration: underline; text-underline-offset: 3px; }
.as-dot { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font-size: var(--as-size-label); font-weight: 600; border: 2px solid var(--as-line-strong); background: var(--as-surface); color: var(--as-text-muted); font-variant-numeric: tabular-nums; }
.as-dot .as-icon { width: 18px; height: 18px; }
.as-step-title { font-weight: 600; line-height: 1.35; padding-top: 4px; }
.as-steps__meta { display: block; font-size: var(--as-size-label); font-weight: 400; color: var(--as-text-muted); line-height: 1.4; margin-top: 2px; }
[data-state="done"] > .as-steps__link .as-dot { background: var(--as-primary); border-color: var(--as-primary); color: var(--as-on-primary); }
[data-state="current"] > .as-steps__link .as-dot { border-color: var(--as-primary); color: var(--as-text); box-shadow: 0 0 0 4px var(--as-selected-bg); }
[data-state="current"] .as-steps__meta { color: var(--as-text-accent); font-weight: 600; }
[data-state="todo"] .as-step-title { color: var(--as-text-muted); font-weight: 500; }

/* Step card: one place to look, its routes, a script to read and a checklist. */
.as-step { background: var(--as-surface); border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius-lg); padding: var(--as-space-6); display: grid; gap: var(--as-space-5); min-width: 0; }
.as-step__head { display: grid; gap: var(--as-space-2); }
/* Why this step: one short reason under the title, always shown, so each step
   says what it's for before what to do. The longer why opens in place. */
.as-step__why { display: grid; justify-items: start; gap: var(--as-space-1); max-width: var(--as-measure); border-left: 3px solid var(--as-scent); padding-left: var(--as-space-4); margin-top: var(--as-space-1); }
.as-step__why p { margin: 0; line-height: var(--as-lh-body); }
.as-step__why strong { display: block; font-size: var(--as-size-label); font-weight: 600; color: var(--as-text-accent); }
.as-step__why details > p { margin-top: var(--as-space-1); font-size: var(--as-size-small); color: var(--as-text-muted); }
.as-step__why .as-disclose { font-size: var(--as-size-small); }
.as-script { border-left: 3px solid var(--as-scent); padding: var(--as-space-1) 0 var(--as-space-1) var(--as-space-4); font-family: var(--as-font-display); font-size: var(--as-size-body); line-height: 1.5; margin: 0; }
.as-step-nav { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--as-space-3); }
/* To-do: a step's one list. Each item is the instruction and its tick, with
   any words to say under it; [data-next] marks the next one to do. */
.as-todo { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-2); }
.as-todo__item { position: relative; display: grid; gap: var(--as-space-2); padding: var(--as-space-3) var(--as-space-4); background: var(--as-surface); border: var(--as-border-control) solid var(--as-line); border-radius: var(--as-radius); }
/* The next one to do has a plum edge. Each item holds its own edge, hidden
   and parked a little toward the next one, so when the next one changes the
   edge slides off one item and onto the other (1.19.0). */
.as-todo__item::after { content: ""; position: absolute; inset: calc(-1 * var(--as-border-control)); border: var(--as-border-control) solid var(--as-primary); border-radius: inherit; box-shadow: 0 0 0 1px var(--as-primary); pointer-events: none; opacity: 0; transform: translateY(var(--as-space-3)); transition: opacity var(--as-dur) var(--as-ease), transform var(--as-dur-slow) var(--as-ease-spring); }
.as-todo__item[data-next] ~ .as-todo__item::after { transform: translateY(calc(-1 * var(--as-space-3))); }
.as-todo__item[data-next]::after { opacity: 1; transform: none; }
.as-todo__tick { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 2px var(--as-space-3); align-items: start; min-height: var(--as-target); cursor: pointer; }
.as-todo__tick input { grid-row: span 2; }
.as-todo__title { font-weight: 600; line-height: 1.4; padding-top: 1px; transition: color var(--as-dur) var(--as-ease); }
.as-todo__detail { grid-column: 2; font-size: var(--as-size-small); color: var(--as-text-muted); line-height: 1.5; }
.as-todo__item:has(input:checked) .as-todo__title { color: var(--as-text-muted); }
/* Strike: a line that draws across the words when their tick goes on (1.19.0).
   Wrap the words in it so a line that wraps is struck to its end. It draws by
   growing a background, which repaints but never moves anything. */
.as-strike { background: linear-gradient(var(--as-line-strong), var(--as-line-strong)) no-repeat 0 58% / 0 var(--as-border-control); transition: background-size var(--as-dur-slow) var(--as-ease-spring); }
:checked ~ * .as-strike, :checked ~ .as-strike { background-size: 100% var(--as-border-control); }
.as-todo__item .as-script { margin-left: calc(24px + var(--as-space-3)); font-size: var(--as-size-small); }
/* Step bar: one strip under the app bar on every guide screen. It says which
   step you're on and drops the step list down over the page, so nothing under it moves. */
.as-stepbar { position: relative; background: var(--as-surface); border-bottom: var(--as-border) solid var(--as-line); }
.as-stepbar__btn { display: flex; align-items: center; gap: var(--as-space-3); width: 100%; max-width: var(--as-col); min-height: var(--as-target); margin: 0 auto; padding-block: var(--as-space-2); padding-left: max(var(--as-space-4), env(safe-area-inset-left, 0px)); padding-right: max(var(--as-space-4), env(safe-area-inset-right, 0px)); border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.as-stepbar__segs { display: flex; gap: var(--as-space-1); flex: none; }
.as-stepbar__segs i { position: relative; overflow: hidden; width: 20px; height: 6px; border-radius: var(--as-radius-pill); background: var(--as-surface-sunk); }
/* Each segment fills from the left with a spring when its state changes
   (1.19.0): plum for now, marigold for waiting, then green sweeps over it when
   the step is done. */
.as-stepbar__segs i::before, .as-stepbar__segs i::after { content: ""; position: absolute; inset: 0; border-radius: inherit; transform: scaleX(0); transform-origin: left; transition: transform var(--as-dur-slow) var(--as-ease-spring); }
.as-stepbar__segs i::before { background: var(--as-primary); }
.as-stepbar__segs i::after { background: var(--as-found); }
.as-stepbar__segs [data-state="waiting"]::before { background: var(--as-tag); }
.as-stepbar__segs :is([data-state="current"], [data-state="waiting"])::before, .as-stepbar__segs [data-state="done"]::after { transform: none; }
.as-stepbar__label { flex: 1; min-width: 0; font-size: var(--as-size-label); line-height: 1.35; color: var(--as-text-muted); }
.as-stepbar__label b { font-weight: 600; color: var(--as-text); }
.as-stepbar__btn > .as-icon { flex: none; transform: rotate(90deg); transition: transform var(--as-dur) var(--as-ease); }
.as-stepbar__btn[aria-expanded="true"] > .as-icon { transform: rotate(-90deg); }
.as-stepbar__panel { position: absolute; top: 100%; left: 0; right: 0; max-height: calc(100vh - var(--as-masthead-h)); max-height: calc(100dvh - var(--as-masthead-h)); overflow-y: auto; overscroll-behavior: contain; display: grid; gap: var(--as-space-3); padding-block: var(--as-space-2) var(--as-space-4); padding-left: max(var(--as-space-4), env(safe-area-inset-left, 0px), calc((100% - var(--as-col)) / 2 + var(--as-space-4))); padding-right: max(var(--as-space-4), env(safe-area-inset-right, 0px), calc((100% - var(--as-col)) / 2 + var(--as-space-4))); background: var(--as-surface); border-bottom: var(--as-border) solid var(--as-line); box-shadow: var(--as-shadow-2); }
/* A step that waits on mail: marigold, between to do and done. */
[data-state="waiting"] > .as-steps__link .as-dot { background: var(--as-tag); border-color: var(--as-tag); color: var(--as-on-tag); }
[data-state="waiting"] .as-steps__meta { color: var(--as-waiting); font-weight: 600; }
/* Action bar: a screen's next move, pinned to the bottom of the screen while
   the page scrolls. The ground and the line reach both edges. */
.as-actionbar { position: sticky; bottom: 0; z-index: 2; display: grid; gap: var(--as-space-1); padding-top: var(--as-space-3); padding-bottom: calc(var(--as-space-3) + env(safe-area-inset-bottom, 0px)); background: var(--as-bg); box-shadow: 0 0 0 100vmax var(--as-bg); clip-path: inset(0 -100vmax); }
/* The top line reaches both edges by its shadow, clipped to its own height, so it never widens the page. */
.as-actionbar::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: var(--as-border); background: var(--as-line); box-shadow: 0 0 0 100vmax var(--as-line); clip-path: inset(0 -100vmax); }
/* Welcome back: where a returning person left off, and the next thing to do. */
.as-resume { display: grid; gap: var(--as-space-4); }
.as-resume__next { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 2px var(--as-space-3); align-items: start; padding: var(--as-space-3) var(--as-space-4); background: var(--as-surface); border: var(--as-border-control) solid var(--as-primary); border-radius: var(--as-radius); }
.as-resume__next > .as-icon { grid-row: span 2; margin-top: 2px; color: var(--as-text-accent); }
.as-resume__next small { grid-column: 2; font-size: var(--as-size-label); color: var(--as-text-muted); }
/* As a link it opens that step: underline the title on hover, like the step list. */
a.as-resume__next { color: inherit; text-decoration: none; }
a.as-resume__next:hover b { text-decoration: underline; text-underline-offset: 3px; }

/* Routes: ways to find the account, most to least likely. */
.as-routes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-4); counter-reset: route; }
.as-routes li { counter-increment: route; display: grid; grid-template-columns: 32px minmax(0, 1fr); gap: 2px var(--as-space-3); }
.as-routes li::before { content: counter(route); grid-row: span 2; width: 32px; height: 32px; border-radius: 50%; background: var(--as-surface-sunk); display: grid; place-items: center; font-size: var(--as-size-label); font-weight: 600; font-variant-numeric: tabular-nums; }
.as-routes li:first-child::before { background: var(--as-primary); color: var(--as-on-primary); }
.as-routes strong { font-weight: 600; line-height: 1.4; padding-top: 3px; }
.as-routes span { font-size: var(--as-size-small); color: var(--as-text-muted); }

/* Checklist */
.as-checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-2); }
.as-check { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--as-space-3); align-items: start; min-height: var(--as-target); padding-block: var(--as-space-2); cursor: pointer; }
.as-check input, .as-todo__tick input, .as-file input { appearance: none; margin: 2px 0 0; width: 24px; height: 24px; border: 2px solid var(--as-line-strong); border-radius: 6px; background: var(--as-surface); display: grid; place-content: center; cursor: pointer; transition: background var(--as-dur-fast) var(--as-ease), border-color var(--as-dur-fast) var(--as-ease); }
.as-check input::after, .as-todo__tick input::after, .as-file input::after { content: ""; width: 12px; height: 7px; border-left: 2.5px solid var(--as-on-primary); border-bottom: 2.5px solid var(--as-on-primary); transform: rotate(-45deg) scale(0); margin-top: -3px; transition: transform var(--as-dur) var(--as-ease-pop); }
.as-check input:checked, .as-todo__tick input:checked, .as-file input:checked { background: var(--as-primary); border-color: var(--as-primary); }
.as-check input:checked::after, .as-todo__tick input:checked::after, .as-file input:checked::after { transform: rotate(-45deg) scale(1); }
.as-check input:checked + span { color: var(--as-text-muted); text-decoration: line-through; text-decoration-color: var(--as-line-strong); }

/* What you'll need: short icon list on the guide overview. */
.as-needs { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-3); }
.as-needs li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--as-space-3); font-size: var(--as-size-small); }
.as-needs .as-icon { color: var(--as-text-accent); }

/* "Needs checking" marker on facts Bret has not confirmed yet. */
.as-verify { display: inline-flex; gap: 6px; align-items: center; font: 600 var(--as-size-label)/1.3 var(--as-font-body); color: var(--as-waiting); background: var(--as-waiting-bg); border-radius: var(--as-radius-pill); padding: 4px 10px; }
.as-verify .as-icon { width: 14px; height: 14px; }

/* ---------- Account sheet ---------- */
.as-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: var(--as-space-3); margin: 0; }
.as-stat { background: var(--as-surface); border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius); padding: var(--as-space-4); display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: var(--as-space-2); margin: 0; }
.as-stat dd { margin: 0; font-family: var(--as-font-display); font-size: var(--as-size-h2); line-height: 1; font-variant-numeric: tabular-nums; }
.as-stat dt { font-size: var(--as-size-label); color: var(--as-text-muted); }
/* The week before, under the number (admin). order keeps it last on screen and in reading order. */
.as-stat .as-stat__was { order: -1; font: 400 var(--as-size-caption)/1.4 var(--as-font-body); color: var(--as-text-muted); }

/* Status chips: confirmed (found), waiting to hear (looking), needs something
   (blocked), to ask (todo) and nothing there (none, no dot). */
.as-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px; border-radius: var(--as-radius-pill); font-size: var(--as-size-label); font-weight: 600; line-height: 1.4; white-space: nowrap; }
.as-chip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.as-chip--found { background: var(--as-found-bg); color: var(--as-found); }
.as-chip--looking { background: var(--as-waiting-bg); color: var(--as-waiting); }
.as-chip--blocked { background: var(--as-blocked-bg); color: var(--as-blocked); }
.as-chip--todo { background: var(--as-surface-sunk); color: var(--as-text-muted); }
.as-chip--todo::before { background: transparent; border: 1.5px solid currentColor; }
.as-chip--none { background: var(--as-surface-sunk); color: var(--as-text-muted); }
.as-chip--none::before { display: none; }

/* Account rows. On phones the chip drops under the name. */
.as-inv { display: grid; border-top: var(--as-border) solid var(--as-line); }
.as-inv-row { display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: var(--as-space-2) var(--as-space-4); align-items: center; padding: var(--as-space-4) var(--as-space-2); border-bottom: var(--as-border) solid var(--as-line); color: inherit; text-decoration: none; transition: background var(--as-dur-fast) var(--as-ease), transform var(--as-dur-fast) var(--as-ease-spring); }
a.as-inv-row:hover { background: var(--as-surface-sunk); }
.as-inv-row > div { min-width: 0; }
.as-inv-row__icon { width: 40px; height: 40px; border-radius: var(--as-radius-sm); background: var(--as-selected-bg); display: grid; place-items: center; color: var(--as-text); }
.as-inv-row__icon .as-icon { width: 22px; height: 22px; }
.as-inv-row__name { font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.as-inv-row__meta { font-size: var(--as-size-label); color: var(--as-text-muted); line-height: 1.4; }
/* An account that opens in place: its next move under the name, and a chevron
   that turns when open. --next keeps the chevron on the row on phones. */
.as-inv-row__next { display: block; font-size: var(--as-size-label); font-weight: 600; color: var(--as-text-accent); line-height: 1.4; }
.as-inv-row__chev { color: var(--as-text-muted); transition: transform var(--as-dur-fast) var(--as-ease); }
.as-inv-row[aria-expanded="true"] .as-inv-row__chev { transform: rotate(90deg); }
.as-inv-row--next { grid-template-columns: 40px minmax(0, 1fr) 24px; }
/* What opens under an account: the track, the next move, the details. */
.as-inv-open { display: grid; gap: var(--as-space-4); padding: var(--as-space-2) var(--as-space-2) var(--as-space-5); border-bottom: var(--as-border) solid var(--as-line); }
/* A status group on the sheet: its chip and how many. */
.as-inv-group { display: grid; gap: var(--as-space-2); }
.as-inv-group__head { display: flex; justify-content: space-between; align-items: center; gap: var(--as-space-3); }

/* Track: an account's three stops, heard the name, asked them, got an answer. */
.as-track { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--as-space-1); margin: 0; padding: 0; list-style: none; }
.as-track li { display: grid; gap: 6px; font-size: var(--as-size-caption); color: var(--as-text-muted); line-height: 1.3; }
.as-track li::before { content: ""; height: 6px; border-radius: 3px; background: var(--as-surface-sunk); }
.as-track li[data-on]::before { background: var(--as-scent); }
.as-track li[data-on] { color: var(--as-text); font-weight: 600; }

/* Capture: the "names you found here" box at the end of a guide step. One
   field and an Add button; each name lands in the list under it at once. */
.as-capture { background: var(--as-surface); border: 2px solid var(--as-scent); border-radius: var(--as-radius-lg); padding: var(--as-space-4); display: grid; gap: var(--as-space-3); }
.as-capture__head { display: flex; align-items: center; gap: var(--as-space-3); }
.as-capture__head > div { min-width: 0; }
.as-capture__form { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--as-space-2); align-items: start; }
.as-capture__form .as-field__error { grid-column: 1 / -1; }
.as-capture__list { display: grid; }
.as-capture__list .as-inv-row { grid-template-columns: 40px minmax(0, 1fr) auto; padding-inline: 0; }
.as-capture__list .as-inv-row:last-child { border-bottom: 0; }

/* Ask: a short question in place, answered with pills (what kind is this?). */
.as-ask { grid-column: 1 / -1; display: grid; gap: var(--as-space-2); background: var(--as-info-bg); border-radius: var(--as-radius-sm); padding: var(--as-space-3); }
.as-ask > p { margin: 0; font-size: var(--as-size-small); font-weight: 600; }

/* ---------- Forms ---------- */
.as-field { display: grid; gap: var(--as-space-2); }
.as-field__label { font-size: var(--as-size-small); font-weight: 600; }
.as-field__hint { font-size: var(--as-size-label); color: var(--as-text-muted); }
.as-field__error { font-size: var(--as-size-label); color: var(--as-blocked); font-weight: 500; }
.as-input { width: 100%; min-height: var(--as-target); padding: var(--as-space-3) var(--as-space-4); font: inherit; font-size: var(--as-size-body); color: var(--as-text); background: var(--as-surface); border: var(--as-border-control) solid var(--as-line-strong); border-radius: var(--as-radius-sm); }
.as-input::placeholder { color: var(--as-text-muted); opacity: .8; }
.as-input:focus-visible { border-color: var(--as-text); }
.as-input[aria-invalid="true"] { border-color: var(--as-blocked); }
textarea.as-input { min-height: 120px; resize: vertical; line-height: var(--as-lh-body); }
.as-select { position: relative; }
.as-select select.as-input { appearance: none; -webkit-appearance: none; padding-right: var(--as-space-7); cursor: pointer; }
.as-select::after { content: ""; position: absolute; right: 20px; top: 50%; width: 9px; height: 9px; border-right: 2px solid var(--as-text); border-bottom: 2px solid var(--as-text); transform: translateY(-70%) rotate(45deg); pointer-events: none; }

/* Segmented control (radio group): lane switch. */
.as-seg { display: inline-flex; flex-wrap: wrap; gap: 4px; padding: 4px; border: 0; margin: 0; border-radius: var(--as-radius); background: var(--as-surface-sunk); }
.as-seg label { position: relative; display: block; }
.as-seg input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.as-seg span { display: inline-flex; align-items: center; min-height: var(--as-target); padding: 0 var(--as-space-4); border-radius: var(--as-radius-sm); font-size: var(--as-size-small); font-weight: 500; color: var(--as-text-muted); }
.as-seg input:checked + span { background: var(--as-surface); color: var(--as-text); font-weight: 600; box-shadow: var(--as-shadow-1); }
.as-seg input:focus-visible + span { box-shadow: var(--as-focus-ring); }

/* Invite code shown to a helper. */
.as-code-card { background: var(--as-surface-sunk); border-radius: var(--as-radius); padding: var(--as-space-4) var(--as-space-5); display: grid; gap: var(--as-space-2); }
.as-code { font-family: var(--as-font-display); font-size: var(--as-size-code); letter-spacing: .18em; line-height: 1.1; color: var(--as-text); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ---------- Navigation ---------- */
/* Masthead: the app bar and, in the guide, the step bar under it, pinned
   together to the top while the page scrolls. The app keeps --as-masthead-h at
   its height, so other pinned parts and anything scrolled to land below it. Short
   screens (a phone on its side) let it scroll away to keep room for the page. */
.as-masthead { position: sticky; top: 0; z-index: 3; }
.as-masthead > .as-appbar { position: static; }
.as-screen :where(*) { scroll-margin-top: calc(var(--as-masthead-h) + var(--as-space-2)); }
@media (max-height: 30rem) { .as-masthead { position: relative; } }
.as-appbar { position: sticky; top: env(safe-area-inset-top, 0px); z-index: 3; background: var(--as-bg); border-bottom: var(--as-border) solid var(--as-line); padding-block: var(--as-space-3); padding-left: max(var(--as-space-4), env(safe-area-inset-left, 0px)); padding-right: max(var(--as-space-4), env(safe-area-inset-right, 0px)); }
.as-appbar__in { max-width: var(--as-wide); margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: var(--as-space-3); }
.as-appbar__end { display: flex; align-items: center; gap: 6px; }

.as-tabs { display: flex; gap: var(--as-space-1); border-bottom: var(--as-border) solid var(--as-line); overflow-x: auto; scrollbar-width: none; }
.as-tab { display: inline-flex; align-items: center; gap: var(--as-space-2); min-height: var(--as-target); padding: 0 var(--as-space-4); border: 0; border-bottom: 3px solid transparent; background: none; color: var(--as-text-muted); font: 500 var(--as-size-small)/1 var(--as-font-body); cursor: pointer; white-space: nowrap; text-decoration: none; }
.as-tab:hover { color: var(--as-text); }
.as-tab[aria-current="page"], .as-tab[aria-selected="true"] { color: var(--as-text); border-bottom-color: var(--as-primary); font-weight: 600; }

/* ---------- States ---------- */
.as-empty { display: grid; justify-items: center; text-align: center; gap: var(--as-space-3); padding: var(--as-space-7) var(--as-space-5); }
.as-empty .as-art { width: min(150px, 50%); }
.as-loader { display: grid; justify-items: center; gap: var(--as-space-4); text-align: center; padding: var(--as-space-7) 0; }
.as-loader .as-art { width: min(240px, 66%); }
.as-toast { position: fixed; left: 50%; bottom: calc(var(--as-space-5) + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); width: min(440px, calc(100% - 2 * var(--as-space-4))); z-index: 10; box-shadow: var(--as-shadow-2); }

/* ---------- Document Sniff ----------
   The paid add-on's screens: the offer, the invitation as it lands in an
   inbox, the loved one's side (one size up), picking files to send, and the
   report. Used by the Document Sniff preview (AS-16). */
/* Offer card body: the words, with the sniffer beside them. Sits in .as-card--offer. */
.as-offer { display: grid; grid-template-columns: minmax(0, 1fr) 88px; gap: var(--as-space-4); align-items: center; }
.as-offer .as-art { width: 88px; }
/* Price line: the amount large, then what it covers. */
.as-price { margin: 0; display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--as-space-2); }
.as-price b { font: 400 var(--as-size-h2)/1.1 var(--as-font-display); }
/* Promise list: what it will never do, a record of every step, what looks missing. Icon, then words. */
.as-promise { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-3); }
.as-promise li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--as-space-3); font-size: var(--as-size-small); }
.as-promise .as-icon { color: var(--as-text-accent); }
/* A note in someone's own words keeps their line breaks. */
.as-script--note { font-family: var(--as-font-body); font-size: var(--as-size-small); white-space: pre-wrap; margin-top: var(--as-space-2); }
/* Email preview: the invitation as it lands in an inbox. */
.as-mail { gap: var(--as-space-4); }
.as-mail__meta { display: grid; gap: 2px; font-size: var(--as-size-label); color: var(--as-text-muted); border-bottom: var(--as-border) solid var(--as-line); padding-bottom: var(--as-space-3); overflow-wrap: anywhere; }
.as-mail__meta b { color: var(--as-text); }
/* View bar: whose side of Document Sniff a screen shows. */
.as-viewbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--as-space-2) var(--as-space-3); background: var(--as-surface-inverse); color: var(--as-text-inverse); border-radius: var(--as-radius); padding: var(--as-space-3) var(--as-space-4); font-size: var(--as-size-label); line-height: 1.4; }
.as-viewbar > span { flex: 1 1 160px; }
.as-viewbar .as-btn { color: var(--as-text-inverse); border-color: currentColor; }
/* The loved one's screens run a size up, with 56px buttons. */
.as-helper { font-size: var(--as-size-body-lg); }
.as-helper .as-btn { min-height: var(--as-target-lg); font-size: var(--as-size-body); }
.as-helper .as-art { width: min(200px, 56%); justify-self: center; }
/* File choice: one file to send or keep, with why it was picked. --held is a file we left unticked. */
.as-file { display: grid; grid-template-columns: 24px 32px minmax(0, 1fr); gap: var(--as-space-3); align-items: start; padding: var(--as-space-3) var(--as-space-4); background: var(--as-surface); border: var(--as-border-control) solid var(--as-line); border-radius: var(--as-radius); cursor: pointer; font-size: var(--as-size-small); transition: background var(--as-dur-fast) var(--as-ease), transform var(--as-dur-fast) var(--as-ease-spring); }
.as-file:has(input:checked) { border-color: var(--as-primary); }
.as-file__icon { width: 32px; height: 32px; border-radius: var(--as-radius-sm); background: var(--as-selected-bg); display: grid; place-items: center; }
.as-file__icon .as-icon { width: 18px; height: 18px; }
.as-file__body { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.as-file__why { font-size: var(--as-size-label); line-height: 1.45; }
.as-file--held { background: var(--as-blocked-bg); border-style: dashed; }
/* Show more: a longer list that opens in place. */
.as-more { border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius); padding: var(--as-space-1) var(--as-space-4); display: grid; transition: border-color var(--as-dur-fast) var(--as-ease); }
.as-more:hover { border-color: var(--as-line-strong); }
.as-more > summary { cursor: pointer; font-weight: 600; font-size: var(--as-size-small); min-height: var(--as-target); display: flex; align-items: center; justify-content: space-between; gap: var(--as-space-3); list-style: none; border-radius: var(--as-radius-sm); }
.as-more[open] { gap: var(--as-space-3); padding-bottom: var(--as-space-4); }
/* Opens in place: any <summary> or toggle button gets an .as-chev at its end.
   It points down when closed and up when open, so a tap is the obvious move. */
.as-more > summary::-webkit-details-marker, .as-disclose::-webkit-details-marker { display: none; }
.as-disclose { display: inline-flex; align-items: center; gap: var(--as-space-2); min-height: var(--as-target); cursor: pointer; list-style: none; }
.as-chev { flex: none; color: var(--as-text-muted); transform: rotate(90deg); transition: transform var(--as-dur-fast) var(--as-ease); }
.as-link > .as-chev, .as-disclose > .as-chev { color: inherit; }
details[open] > summary > .as-chev { transform: rotate(-90deg); }
/* Preview aside: a note that only a preview shows, like "try their side". */
.as-callout--preview { background: var(--as-surface); border: 1.5px dashed var(--as-text-accent); }
/* A longer text box, such as a note. */
.as-input--area { min-height: 168px; resize: vertical; line-height: 1.5; }

/* ---------- Admin (AS-49) ----------
   Broc and Bret's private /admin view of our own counts, the email list,
   invitations and problems. Plain and dense, but phone first like the rest. */
/* Data table: names on the left, numbers right-aligned in tabular figures
   (__n). On a phone each row becomes a small card, and each cell says what it
   is from its data-label; the row's first cell is its name. */
.as-table { width: 100%; border-collapse: collapse; font-size: var(--as-size-small); }
.as-table caption { text-align: left; font-weight: 600; padding-bottom: var(--as-space-2); }
.as-table th, .as-table td { padding: var(--as-space-2) var(--as-space-3); border-bottom: var(--as-border) solid var(--as-line); text-align: left; vertical-align: top; }
.as-table th { font-size: var(--as-size-label); font-weight: 600; color: var(--as-text-muted); }
.as-table td { overflow-wrap: anywhere; }
.as-table :is(th, td).as-table__n { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.as-table tbody tr:last-child td { border-bottom: 0; }
@media (max-width: 479px) {
  .as-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .as-table tr { display: grid; gap: var(--as-space-1); padding-block: var(--as-space-3); border-bottom: var(--as-border) solid var(--as-line); }
  .as-table tbody tr:last-child { border-bottom: 0; }
  .as-table td { display: flex; justify-content: space-between; align-items: baseline; gap: var(--as-space-3); padding: 0; border: 0; }
  .as-table td::before { content: attr(data-label); flex: none; font-size: var(--as-size-label); color: var(--as-text-muted); }
  .as-table td:first-child { display: block; font-weight: 600; }
  .as-table td[colspan] { font-weight: 400; }
  .as-table td:first-child::before, .as-table td:not([data-label])::before { content: none; }
  .as-table :is(th, td).as-table__n { text-align: right; }
}
/* Funnel: each point a family reaches, its count, a bar against the first
   point and the share of the point before. The bar's width is --w on __bar's <i>. */
.as-funnel { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-4); }
.as-funnel li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--as-space-1) var(--as-space-3); align-items: baseline; }
.as-funnel__label { font-size: var(--as-size-small); font-weight: 500; }
.as-funnel__n { font-weight: 600; font-variant-numeric: tabular-nums; }
.as-funnel__bar { grid-column: 1 / -1; height: 10px; border-radius: var(--as-radius-pill); background: var(--as-surface-sunk); overflow: hidden; }
.as-funnel__bar i { display: block; height: 100%; width: var(--w, 0%); min-width: 2px; border-radius: inherit; background: var(--as-primary); }
.as-funnel__rate { grid-column: 1 / -1; font-size: var(--as-size-caption); color: var(--as-text-muted); }

/* ---------- Layout ---------- */
/* Questions sit in one 480px column; guide and sheet split at 768px. */
.as-col { width: 100%; max-width: var(--as-col); margin-inline: auto; padding-left: max(var(--as-space-4), env(safe-area-inset-left, 0px)); padding-right: max(var(--as-space-4), env(safe-area-inset-right, 0px)); }
.as-wide { width: 100%; max-width: var(--as-wide); margin-inline: auto; padding-left: max(var(--as-space-4), env(safe-area-inset-left, 0px)); padding-right: max(var(--as-space-4), env(safe-area-inset-right, 0px)); }
.as-screen { padding-block: var(--as-space-6) var(--as-space-9); }
.as-stack { display: grid; gap: var(--as-space-5); }
.as-stack--sm { gap: var(--as-space-3); }
.as-stack--lg { gap: var(--as-space-6); }
.as-row { display: flex; flex-wrap: wrap; gap: var(--as-space-3); align-items: center; }
.as-split { display: grid; gap: var(--as-space-5); align-items: start; }
.as-split > * { min-width: 0; }
@media (min-width: 768px) {
  .as-split { grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); gap: var(--as-space-6); }
  .as-split--aside-end { grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); }
  .as-sticky { position: sticky; top: calc(var(--as-masthead-h) + var(--as-space-4)); }
}

/* ---------- Wide screens (AS-56) ----------
   Phone first, then more room, and a phone never changes. .as-page goes with
   .as-col: 480px on a phone, 760px (--as-page) from 768px, and with --wide the
   full 1120px from 1024px. Running text keeps its 65ch measure at every width.
   The wrappers below are stacks on a phone (add .as-stack), so nothing moves. */
@media (min-width: 768px) {
  .as-page { max-width: var(--as-page); }
}
@media (min-width: 1024px) {
  .as-page--wide { max-width: var(--as-wide); }

  /* Beside: the words fill the main column and one side block (__side) sits
     in a 360px column on the right, from the top, wherever it is in the
     order. A sniffer that leads the page counts as the side block. --pin
     keeps a short side block in view while the words scroll. Rows don't gap,
     so the side never stretches them; each block keeps its space below. */
  .as-beside { display: grid; grid-template-columns: minmax(0, 1fr) var(--as-aside); column-gap: var(--as-space-8); row-gap: 0; align-items: start; }
  .as-beside > * { grid-column: 1; margin-block-end: var(--as-space-5); }
  .as-beside > :last-child { margin-block-end: 0; }
  .as-beside > :is(.as-beside__side, .as-art:first-child) { grid-column: 2; grid-row: 1 / span 40; margin-block-end: 0; }
  .as-beside > .as-art:first-child { width: 100%; justify-self: center; }
  .as-beside__side--pin { position: sticky; top: calc(var(--as-masthead-h) + var(--as-space-4)); }
  /* An action bar beside a side column keeps to the words' column. */
  .as-beside > .as-actionbar { box-shadow: 0 0 0 var(--as-space-4) var(--as-bg); clip-path: inset(0 calc(-1 * var(--as-space-4))); }
  .as-beside > .as-actionbar::before { box-shadow: 0 0 0 var(--as-space-4) var(--as-line); clip-path: inset(0 calc(-1 * var(--as-space-4))); }

  /* Pair: two or three blocks side by side in equal columns, tops lined up. */
  .as-pair { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-items: start; }

  /* Columns: cards that never change height (like the checklist's sections)
     flow down two columns, so short and long cards pack without gaps. */
  .as-cols { display: block; columns: 2; column-gap: var(--as-space-5); }
  .as-cols > * { break-inside: avoid; margin-block-end: var(--as-space-5); }

  /* An answer that opens in place keeps the reading measure on a wide page. */
  .as-more > :not(summary) { max-width: var(--as-measure); }
  /* The step bar lines up with the wide guide screens under it. */
  .as-stepbar__btn { max-width: var(--as-wide); }
  .as-stepbar__panel { padding-left: max(var(--as-space-4), env(safe-area-inset-left, 0px), calc((100% - var(--as-wide)) / 2 + var(--as-space-4))); padding-right: max(var(--as-space-4), env(safe-area-inset-right, 0px), calc((100% - var(--as-wide)) / 2 + var(--as-space-4))); grid-template-columns: minmax(0, 1fr) var(--as-aside); grid-template-rows: auto 1fr; column-gap: var(--as-space-8); align-items: start; }
  /* The step list on the left; the list link and the other moves beside it. */
  .as-stepbar__panel > :first-child { grid-row: 1 / span 2; }
  .as-stepbar__panel > :not(:first-child) { grid-column: 2; }
}

/* Side panel: the sniffer beside the words on a wide screen, with its tag and
   one quiet line. Only there: a phone already shows the sniffer in the page. */
.as-side { display: none; }
@media (min-width: 1024px) {
  .as-side { display: grid; justify-items: center; gap: var(--as-space-3); text-align: center; background: var(--as-surface); border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius); padding: var(--as-space-6) var(--as-space-5); }
  .as-side .as-art { width: min(220px, 100%); }
  .as-side p { margin: 0; color: var(--as-text-muted); font-size: var(--as-size-small); max-width: 30ch; }
}

/* On this page (AS-65): a long page's parts, listed beside the words from
   1024px and pinned while they scroll (with .as-beside__side--pin). Each link
   glides to its part (.as-anchor), which stops clear of the pinned header; the
   part being read is marked (aria-current). Only there: a phone reads the
   page straight down. A long list scrolls inside itself. */
.as-toc { display: none; }
.as-toc__title { margin: 0; font-size: var(--as-size-caption); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--as-text-muted); }
.as-toc__list { list-style: none; margin: 0; padding: 0; display: grid; border-left: var(--as-border) solid var(--as-line); }
.as-toc__link { display: flex; align-items: center; min-height: 36px; padding: var(--as-space-1) var(--as-space-4); margin-left: calc(-1 * var(--as-border)); border-left: 3px solid transparent; color: var(--as-text-muted); font-size: var(--as-size-label); line-height: 1.4; text-decoration: none; transition: color var(--as-dur-fast) var(--as-ease), border-color var(--as-dur-fast) var(--as-ease); }
.as-toc__link:focus-visible { outline: none; box-shadow: var(--as-focus-ring); }
.as-toc__link:hover { color: var(--as-text); text-decoration: underline; text-underline-offset: 3px; }
.as-toc__link[aria-current] { color: var(--as-text); font-weight: 600; border-left-color: var(--as-scent); }
@media (pointer: coarse) {
  .as-toc__link { min-height: var(--as-target); }
}
@media (min-width: 1024px) {
  .as-toc { display: grid; gap: var(--as-space-3); align-content: start; max-height: calc(100vh - var(--as-masthead-h) - 2 * var(--as-space-4)); max-height: calc(100dvh - var(--as-masthead-h) - 2 * var(--as-space-4)); overflow-y: auto; overscroll-behavior: contain; }
  .as-anchor { scroll-margin-top: calc(var(--as-masthead-h) + var(--as-space-5)); }
  .as-anchor > :first-child:focus { outline: none; } /* a jump moves focus to the part's heading */
}

/* Phones: tighter step card padding; account chips drop under the name. */
@media (max-width: 479px) {
  .as-step { padding: var(--as-space-5) var(--as-space-4); }
  .as-inv-row { grid-template-columns: 40px minmax(0, 1fr); }
  .as-inv-row > .as-chip { grid-column: 2; justify-self: start; }
  .as-inv-row--next { grid-template-columns: 40px minmax(0, 1fr) 24px; }
}

/* ---------- Print (guide and account sheet) ----------
   The app fills .as-print just before printing. While it holds anything, paper
   shows only it: plain type, boxes to tick by hand, and a sheet table with a
   Notes column and blank rows. Tokens switch to light for print (tokens.css).
   .as-print--preview shows it on screen, as the design system page does. */
.as-print { display: none; }
.as-print--preview { display: block; }
@media print {
  @page { margin: 16mm 14mm; }
  .as-body { background: var(--as-surface); }
  .as-body:has(> .as-print:not(:empty)) > :not(.as-print) { display: none !important; }
  .as-print:not(:empty) { display: block; }
}
.as-print { color: var(--as-text); background: var(--as-surface); font: 400 var(--as-size-print)/1.45 var(--as-font-body); }
.as-print p { margin: 0 0 var(--as-space-2); max-width: none; }
.as-print__head { display: grid; gap: var(--as-space-1); padding-bottom: var(--as-space-3); margin-bottom: var(--as-space-4); border-bottom: var(--as-border) solid var(--as-line-strong); }
.as-print__brand { font: 400 var(--as-size-print)/1 var(--as-font-display); color: var(--as-text-muted); }
.as-print__h1 { margin: 0; font: 400 var(--as-size-print-h1)/1.2 var(--as-font-display); text-wrap: balance; }
.as-print__h2 { display: flex; gap: var(--as-space-2); align-items: baseline; margin: 0 0 var(--as-space-2); font: 400 var(--as-size-print-h2)/1.25 var(--as-font-display); break-after: avoid; }
.as-print__h3 { margin: var(--as-space-3) 0 var(--as-space-1); font: 600 var(--as-size-print)/1.3 var(--as-font-body); break-after: avoid; }
.as-print__meta, .as-print__eyebrow, .as-print__foot { font-size: var(--as-size-print-small); color: var(--as-text-muted); }
.as-print__eyebrow { margin: 0 0 var(--as-space-1); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.as-print__section, .as-print__step { margin-bottom: var(--as-space-5); }
.as-print__step { padding-top: var(--as-space-4); border-top: var(--as-border) solid var(--as-line); }
.as-print__stephead { break-inside: avoid; break-after: avoid; }
.as-print__step > p, .as-print__quote, .as-print__list li { break-inside: avoid; }
.as-print__list { margin: 0; padding-left: 1.4em; display: grid; gap: var(--as-space-1); }
.as-print__checks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--as-space-2); }
.as-print__checks li { display: flex; gap: var(--as-space-2); align-items: flex-start; break-inside: avoid; }
.as-print__quote { margin: 0; padding-left: var(--as-space-3); border-left: 3px solid var(--as-line-strong); font-style: italic; }
.as-print__note { margin-top: var(--as-space-3); }
/* A box to tick with a pen; a done one carries a drawn check, no fill, so it prints without backgrounds. */
.as-print__box { position: relative; flex: none; width: 11pt; height: 11pt; margin-top: 1pt; border: 1.2pt solid var(--as-text); border-radius: 2pt; }
.as-print__h2 .as-print__box { width: 12pt; height: 12pt; margin-top: 0; align-self: center; }
.as-print__box--on::after { content: ""; position: absolute; left: 3pt; top: 0; width: 3.5pt; height: 7pt; border: solid var(--as-text); border-width: 0 1.6pt 1.6pt 0; transform: rotate(45deg); }
.as-print__table { width: 100%; border-collapse: collapse; font-size: var(--as-size-print); }
.as-print__table th { text-align: left; font-weight: 600; font-size: var(--as-size-print-small); text-transform: uppercase; letter-spacing: .06em; color: var(--as-text-muted); border-bottom: 1.2pt solid var(--as-text); padding: var(--as-space-1) var(--as-space-2); }
.as-print__table td { border-bottom: var(--as-border) solid var(--as-line-strong); padding: var(--as-space-2); vertical-align: top; }
.as-print__table th:last-child, .as-print__table td:last-child { width: 30%; }
.as-print__table thead { display: table-header-group; }
.as-print__table tr { break-inside: avoid; }
.as-print__blank td { height: 22pt; }
.as-print__foot { margin-top: var(--as-space-5); padding-top: var(--as-space-2); border-top: var(--as-border) solid var(--as-line); }

/* ---------- Motion (1.17.0) ---------- */
/* Press: a tapped control sinks a little, so every tap answers at once.
   Transform only, so nothing around it moves. */
.as-btn:active:not(:is([disabled], [aria-disabled="true"])), .as-pill:active, .as-theme:active { transform: scale(var(--as-press)); }
.as-choice:active, .as-breed:active, a.as-inv-row:active, a.as-resume__next:active, .as-file:active { transform: scale(var(--as-press-card)); }
a.as-resume__next { transition: transform var(--as-dur-fast) var(--as-ease-spring); }

/* The step bar's list drops in from under the bar. */
.as-stepbar__panel:not([hidden]) { animation: as-drop var(--as-dur) var(--as-ease-spring); }
@keyframes as-drop { from { opacity: 0; transform: translateY(calc(-1 * var(--as-space-2))); } }

/* Screen changes: the app wraps each change in a view transition. The app bar
   and step bar hold still; the new screen slides in over the old one (from the
   right going on, from the left going back). Browsers without view
   transitions swap at once. The app skips it when motion is reduced. */
.as-masthead { view-transition-name: as-masthead; }
::view-transition-group(root) { animation-duration: var(--as-dur-screen); }
::view-transition { background: var(--as-bg); } /* the page color behind both screens, never a flash */
::view-transition-old(root) { animation: as-screen-out var(--as-dur-fast) var(--as-ease) both; }
::view-transition-new(root) { animation: as-screen-in var(--as-dur-screen) var(--as-ease-spring) both; }
:root[data-nav="back"]::view-transition-new(root) { animation-name: as-screen-back; }
::view-transition-group(as-masthead) { animation-duration: var(--as-dur); }
@keyframes as-screen-out { to { opacity: 0; } }
@keyframes as-screen-in { from { opacity: 0; transform: translateX(var(--as-shift)); } }
@keyframes as-screen-back { from { opacity: 0; transform: translateX(calc(-1 * var(--as-shift))); } }

/* ---------- Your pace (1.21.0) ---------- */
/* Questions never move on by themselves. Picking an answer only picks it, and
   Continue (always there, so nothing shifts) wakes up. Tapping Continue
   carries them on calmly: into, between and out of the questions the old
   screen fades away, then the new one settles up into place. Slower than a
   screen slide and with no overshoot, so the person feels they set the pace. */
:root[data-nav="calm"]::view-transition-group(root) { animation-duration: var(--as-dur-calm); }
:root[data-nav="calm"]::view-transition-old(root) { animation: as-calm-out var(--as-dur-screen) var(--as-ease-calm) both; }
:root[data-nav="calm"]::view-transition-new(root) { animation: as-calm-in var(--as-dur-calm) var(--as-ease-calm) var(--as-dur-calm-gap) both; }
@keyframes as-calm-out { to { opacity: 0; } }
@keyframes as-calm-in { from { opacity: 0; transform: translateY(var(--as-rise-calm)); } }

/* Opens in place, smoothly where the browser can size to auto. Others open at once. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  details::details-content { height: 0; overflow: clip; transition: height var(--as-dur) var(--as-ease-spring), content-visibility var(--as-dur) allow-discrete; }
  details[open]::details-content { height: auto; }
}

/* ---------- Moments (1.18.0) ---------- */
/* Rolling number: each digit rolls to its new value, so a count climbs
   instead of jumping. roll() in web/motion.js writes it: the plain number for
   screen readers, then one column per digit (--d) and comma. Leading columns
   (data-lead) wait hidden until the number grows into them. Browsers without
   the lh unit show the digits still. --up rolls each digit up from 0 when the
   number first appears, after its .as-reveal turn. */
.as-roll { white-space: nowrap; font-variant-numeric: tabular-nums lining-nums; }
/* Each column is a little taller than the digit, so the digits above and
   below never peek in; the negative margin keeps the line its usual height. */
.as-roll__d { position: relative; display: inline-block; line-height: 1.25; margin-block: -.125em; counter-reset: as-d var(--d); }
.as-roll__d::after { content: counter(as-d); }
.as-roll__s::after { content: ","; }
.as-roll [data-lead] { display: none; }
@supports (height: 1lh) {
  .as-roll__d { clip-path: inset(0); }
  .as-roll__d::after { visibility: hidden; }
  .as-roll__d::before { content: "0\A 1\A 2\A 3\A 4\A 5\A 6\A 7\A 8\A 9"; white-space: pre; position: absolute; top: 0; inset-inline: 0; text-align: center; transform: translateY(calc(var(--d) * -1lh)); transition: transform var(--as-dur) var(--as-ease-spring); }
  .as-roll--up .as-roll__d::before { animation: as-roll-up var(--as-dur-slow) var(--as-ease-spring) backwards; animation-delay: calc(var(--i, 0) * var(--as-stagger)); }
}
@keyframes as-roll-up { from { transform: translateY(0); } }

/* Arrival: a part fades up by --as-rise when it first appears, one after
   another in --i order (0, 1, 2 ...), --as-stagger apart. A repaint in
   place keeps the part, so it never plays twice. For a payoff (results, the
   report) and the next move after it, never for words someone is reading. */
.as-reveal { animation: as-rise var(--as-dur-slow) var(--as-ease-spring) backwards; animation-delay: calc(var(--i, 0) * var(--as-stagger)); }
@keyframes as-rise { from { opacity: 0; transform: translateY(var(--as-rise)); } }

/* Swap: words that change in place (a headline, the folder being looked at)
   rise in. The app gives new words a new data-key, so they arrive fresh. */
.as-swap { display: inline-block; animation: as-rise var(--as-dur) var(--as-ease-spring) backwards; }

/* Pop: lands with a small overshoot, once, when it first appears. For a check
   that just turned done. */
.as-pop { animation: as-pop var(--as-dur) var(--as-ease-pop) backwards; }
@keyframes as-pop { from { opacity: 0; transform: scale(.4); } }

/* Spinner: a small turning arc for something happening now. On its own it is
   1em, for a button at work; inside .as-dot it rings the step that's
   happening. With reduced motion it holds still. */
.as-spin { display: inline-block; flex: none; width: 1em; height: 1em; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent; animation: as-spin var(--as-dur-spin) linear infinite; }
.as-dot:has(> .as-spin) { position: relative; }
.as-dot > .as-spin { position: absolute; inset: -4px; width: auto; height: auto; color: var(--as-primary); border-color: currentColor transparent transparent transparent; }
@keyframes as-spin { to { transform: rotate(1turn); } }

/* Count chip: how many, inside a button ("Send [3 files] to ..."). It pops in
   with the first tick, and its number rolls as ticks change. The words around
   it sit in one .as-btn__label, so a long label wraps as a sentence. --as-on-primary
   on --as-primary, turned around, so it reads in both themes. */
.as-btn__count { display: inline-block; white-space: nowrap; padding: var(--as-space-1) var(--as-space-2); border-radius: var(--as-radius-pill); background: var(--as-on-primary); color: var(--as-primary); font-weight: 600; line-height: 1; animation: as-pop var(--as-dur) var(--as-ease-pop) backwards; }
.as-btn__label { line-height: 1.6; }
.as-btn[aria-busy="true"] { cursor: progress; }

/* ---------- Guide moments (1.19.0) ---------- */
/* Drop: a part that just came drops in from above, once: a name just added,
   one put back, the note that a step is done. A repaint keeps it, so it never
   plays twice. */
.as-drop { animation: as-drop var(--as-dur-slow) var(--as-ease-spring) backwards; }
/* Leave: a row taken off folds up and fades before it goes. The app waits
   --as-dur, then the rows under it glide up into the gap. */
.as-leave { animation: as-leave var(--as-dur) var(--as-ease) forwards; transform-origin: top; pointer-events: none; }
@keyframes as-leave { to { opacity: 0; transform: translateY(calc(-1 * var(--as-space-2))) scaleY(.6); } }
/* Glide: a row that changes group slides to its new place, and the rows
   around it make room, over --as-dur-slow with --as-ease-spring. The app
   measures before and after a change and moves only transform. The row that
   moved rides on top (data-moving). */
.as-inv [data-moving] { position: relative; z-index: 1; background: var(--as-bg); }

/* Step done: the found note on the next step drops in once, with the
   sniffer's found pose where the icon would be. After a death it keeps the
   check icon and the quieter words. */
.as-done { animation: as-drop var(--as-dur-slow) var(--as-ease-spring) var(--as-dur-fast) backwards; }
.as-done:has(> .as-art) { grid-template-columns: var(--as-target-lg) minmax(0, 1fr); align-items: center; }
.as-done > .as-art { width: var(--as-target-lg); }

/* Finish: all five steps done. The found pose (sitting, after a death), the
   words, then the list's counts rolling up from 0, one after another. On a
   wide screen whose side panel already shows the sniffer, the card leaves its
   own out. */
.as-finish { display: grid; justify-items: center; gap: var(--as-space-3); text-align: center; background: var(--as-surface); border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius-lg); padding: var(--as-space-6) var(--as-space-5); }
.as-finish .as-art { width: min(200px, 56%); }
.as-finish > :is(.as-h1, .as-h2, .as-p) { margin: 0; text-wrap: balance; }
.as-finish .as-stats { justify-self: stretch; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--as-space-2); text-align: start; }
.as-finish .as-stat { padding: var(--as-space-3); }
@media (min-width: 1024px) {
  .as-beside:has(> .as-side) .as-finish > .as-art { display: none; }
}

/* Quiet: after a death the same motion stays but nothing overshoots. The app
   sets data-quiet on the page; ticks, dots and pops land with the spring. */
[data-quiet] { --as-ease-pop: var(--as-ease-spring); }

/* ---------- Front door (1.20.0) ---------- */
/* Entrance: on the first screen of a visit, the start or a lane page's
   opening parts (the scene, eyebrow, headline, line and button or question)
   rise in by --as-rise-in, one after another, in about 0.6s. The app adds
   .as-enter to the hero only then; a screen reached later slides in instead. */
.as-enter > * { animation: as-rise-in var(--as-dur-slow) var(--as-ease-spring) backwards; animation-delay: calc(var(--i, 0) * var(--as-stagger)); }
.as-enter > :nth-child(2) { --i: 1; }
.as-enter > :nth-child(3) { --i: 2; }
.as-enter > :nth-child(4) { --i: 3; }
.as-enter > :nth-child(5) { --i: 4; }
.as-enter > :nth-child(6) { --i: 5; }
@keyframes as-rise-in { from { opacity: 0; transform: translateY(var(--as-rise-in)); } }

/* In view: a block after the opening words (the promise, the four places,
   What you get, How it works) fades up the first time it scrolls into view,
   and a numbered list in it follows, one item after another. The app sets
   data-in="no" until then, only where it can watch the scroll, so without it
   everything simply shows. Transform and opacity only: nothing shifts. */
.as-inview, .as-inview .as-four > li { transition: opacity var(--as-dur-slow) var(--as-ease-spring), transform var(--as-dur-slow) var(--as-ease-spring); transition-delay: calc((var(--i, 0) + var(--j, 0)) * var(--as-stagger)); }
.as-inview .as-four > li:nth-child(1) { --j: 2; }
.as-inview .as-four > li:nth-child(2) { --j: 3; }
.as-inview .as-four > li:nth-child(3) { --j: 4; }
.as-inview .as-four > li:nth-child(4) { --j: 5; }
/* Hiding is instant (no transition on the way out), so only coming in moves. */
.as-inview[data-in="no"], .as-inview[data-in="no"] .as-four > li { opacity: 0; transform: translateY(var(--as-rise-in)); transition: none; }
@media print { .as-inview[data-in="no"], .as-inview[data-in="no"] .as-four > li { opacity: 1; transform: none; } }

/* Mini-demo: the Document Sniff story in about ten seconds, built only from
   the design system's parts (web/demo.js): Robert's files tick one by one,
   Send counts and turns to "Sent to Sarah", then on Sarah's phone the
   sniffer finds 3 accounts and they arrive one by one. It plays only while
   on screen, three times at most, then rests on its last frame; the button
   under it pauses it. With reduced motion it shows the last frame, still.
   The stage holds both views at their tallest, unseen (__size), so it never
   changes height and nothing under it moves. Nothing in it can be tapped. */
.as-demo { display: grid; gap: var(--as-space-2); width: 100%; max-width: var(--as-col); margin: 0; text-align: start; }
.as-demo__stage { display: grid; background: var(--as-bg); border: var(--as-border) solid var(--as-line); border-radius: var(--as-radius-lg); padding: var(--as-space-4); overflow: hidden; user-select: none; }
.as-demo__stage > * { grid-area: 1 / 1; min-width: 0; }
.as-demo__size { visibility: hidden; }
.as-demo__view { align-self: start; animation: as-rise var(--as-dur-slow) var(--as-ease-spring) backwards; }
.as-demo__view > p { margin: 0; }
.as-demo__head { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--as-space-3); align-items: center; }
.as-demo__head p { margin: 0; }
/* Room for the file names: the mini-demo's files leave out their icon. */
.as-demo .as-file { grid-template-columns: 24px minmax(0, 1fr); }
.as-demo .as-file__icon { display: none; }
.as-demo .as-inv-row { grid-template-columns: 40px minmax(0, 1fr) auto; padding-block: var(--as-space-3); }
.as-demo .as-inv-row > .as-chip { grid-column: auto; }
.as-demo__cap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--as-space-1) var(--as-space-3); }
.as-demo__cap p { margin: 0; flex: 1 1 200px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0ms !important; animation-duration: 0ms !important; }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
}
