/* ==========================================================================
   Fonts. Three files, 76 KB, all served from this origin.

   Martian Mono, Geist and Geist Mono, each under the SIL Open Font Licence 1.1
   (full texts in assets/fonts/OFL-*.txt). These are the latin-subset variable
   woff2 builds Google Fonts serves, downloaded once and committed here: the
   browser fetches them from us and never opens a connection to Google's font
   servers, or anyone else's.

   Martian Mono is the wordmark and the section headings: every glyph the same
   width, square terminals, wide counters. It reads like a readout on a piece
   of hardware, which is the right register for a page whose argument is that
   you can check it. Geist carries the body, because a paragraph set in a
   monospace stops being readable and the privacy policy is the one page
   nobody should have to fight. Geist Mono takes the small technical labels.
   The fourth voice, Georgia in the MiniShrink card, is the reader's own and
   costs no download.

   `font-display: swap` means text is readable in the fallback immediately and
   never invisible, which matters more here than a moment of reflow.
   ========================================================================== */

@font-face {
  font-family: 'Martian Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('/assets/fonts/martian-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/geist-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/geist-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- the palette — tokens.ts PALETTES.assistant.dark --------------------
   The site is dark, and only dark. There is no theme switch and no stored
   preference, which is why there is no JavaScript on this site at all. */
:root {
  --bg: #101116;
  --surface: #1B1D24;
  --surface2: #23252E;
  --text: #ECEDF1;
  --muted: #9A9CA6;
  --faint: #5E606A;
  --accent: #7D96F5;
  --accent-soft: #26304F;
  --on-accent: #0E1013;
  --border: rgba(236, 237, 241, 0.08);
  --rule: rgba(236, 237, 241, 0.16);
  --danger: #E06A60;

  /* The focus ring is deliberately not tinted — see contrast.py. */
  --focus: #7D96F5;

  /* The mark's gap line is painted in whatever is behind the mark, so it has
     to be a variable. The ring and the slash are not: they read --text and
     --accent directly at the point of use, which is what lets a .tint-* class
     on an ancestor re-tint the slash. A `--mark-slash: var(--accent)` here
     would be substituted once, at the root, and never change again. */
  --mark-gap: var(--bg);

  --sans: 'Geist', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  /* The wordmark and the section headings. Wide and fixed-pitch, so headings
     are kept short and sized down: a long sentence in this would be a wall. */
  --display: 'Martian Mono', 'Geist Mono', ui-monospace, Menlo, Consolas,
    monospace;
  /* MiniShrink is the one place the app speaks in a serif. So is the site,
     and this one is the reader's own: no fourth file to download. */
  --serif: Georgia, "Iowan Old Style", "Palatino Linotype", Palatino, serif;
  --mono: 'Geist Mono', ui-monospace, Menlo, Consolas, "DejaVu Sans Mono",
    monospace;

  --measure: 42rem;
  --page: 120rem;
  --radius-card: 16px;
  --radius-tile: 12px;
  --radius-chip: 999px;

  color-scheme: dark;
}

/* Mode tints. They override the accent and nothing else, so the ZERO mark
   inside a card re-tints the way it does in the app, and no text moves. */
.tint-kid { --accent: #FFA057; --accent-soft: #4A351F; }
.tint-shrink { --accent: #8FB29B; --accent-soft: #26332B; }

/* --- reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* The header is sticky, so an in-page anchor has to leave room for it. */
:target { scroll-margin-top: 96px; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body, h1, h2, h3, p, ul, ol, li, dl, dt, dd, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  letter-spacing: -0.005em;
  margin: 0;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

/* --- shared ------------------------------------------------------------- */
/* Full bleed on desktop: no centred column and no symmetric blank margins.
   The gutter is fluid, so it is 20px on a phone and never more than 64px on a
   very wide screen. The 120rem cap only engages past about 1920px, where a
   line of text running the whole width would stop being readable. */
.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: clamp(20px, 4.5vw, 64px);
}

a { color: inherit; }
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--surface);
  color: var(--text);
  padding: 12px 16px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-tile);
  z-index: 10;
}
.skip:focus { left: 12px; top: 12px; }

/* The mark. Geometry is ZeroMark.tsx exactly: ring r30 sw12, a gap line in the
   background colour at sw22, the accent slash at sw12 on top, both running
   24,76 -> 76,24 so they overshoot the ring. */
/* The box is sized by its context; the svg fills it. `display: block` matters:
   several of these are spans that are not flex items. */
.mark-box { display: block; }
.mark { display: block; width: 100%; height: 100%; }
.mark circle { stroke: var(--text); stroke-width: 12; fill: none; }
.mark .gap { stroke: var(--mark-gap); stroke-width: 22; stroke-linecap: round; }
.mark .slash { stroke: var(--accent); stroke-width: 12; stroke-linecap: round; }

.wordmark {
  font-family: var(--display);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-decoration: none;
}

/* --- header ------------------------------------------------------------- */
.site-header {
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  position: sticky;
  top: 0;
  z-index: 5;
}
.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding-block: 16px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--text);
  margin-inline-end: auto;
}
.brand .mark-box { width: 27px; height: 27px; flex: none; }

.site-nav ul {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  align-items: center;
}
.site-nav a {
  text-decoration: none;
  font-size: 15px;
  color: var(--text);
  padding-block: 4px;
  border-bottom: 1px solid transparent;
}
.site-nav a:hover { border-bottom-color: var(--focus); }
.site-nav a[aria-current="page"] { border-bottom-color: var(--focus); }

/* --- hero --------------------------------------------------------------- */
.hero { padding-block: clamp(56px, 12vw, 116px) clamp(40px, 8vw, 72px); }
.hero h1 {
  font-family: var(--display);
  font-size: clamp(38px, 8.5vw, 82px);
  line-height: 1;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-bottom: 22px;
  display: flex;
  align-items: center;
  gap: 0.22em;
}
/* Sized in em so the mark tracks the wordmark at every viewport. */
.hero h1 .mark-box { width: 0.82em; height: 0.82em; flex: none; }
.expansion {
  font-family: var(--sans);
  font-size: clamp(22px, 3.6vw, 32px);
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: -0.035em;
  margin-bottom: 16px;
}
.plain {
  font-size: clamp(18px, 2.4vw, 21px);
  line-height: 1.4;
  letter-spacing: -0.012em;
  max-width: 26ch;
  padding-inline-start: 16px;
  border-inline-start: 3px solid var(--accent);
}
.availability {
  margin-top: 34px;
  font-size: 15px;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-tile);
  padding: 14px 16px;
  max-width: 42rem;
}

/* The one forward-looking block on the site.
   It borrows .availability's tile so it reads as the same kind of aside — a
   status note beside the product, not a claim about it — and is set a step
   quieter than the copy above it, because everything here is a plan and the
   page's argument rests on things that already exist. The label is the mono
   treatment the eyebrows use, without the accent rule: a rule across the tile
   would give a roadmap the visual weight of a section. */
.roadmap {
  margin-top: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-tile);
  padding: 16px;
  max-width: 42rem;
}
.roadmap-label {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 10px;
}
.roadmap-lede {
  font-size: 17px;
  line-height: 1.35;
  letter-spacing: -0.02em;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 8px;
}
.roadmap-body {
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted);
}
/* Labels, not controls. No hover, no pointer, nothing that suggests a tap:
   three chips that look like buttons and do nothing is the kind of small lie
   this site cannot afford. */
.roadmap-sizes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
  list-style: none;
}
.roadmap-sizes li {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--text);
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 11px;
}

/* --- sections ----------------------------------------------------------- */
section { padding-block: clamp(40px, 7vw, 68px); }
section + section { border-top: 1px solid var(--border); }

.eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}
.eyebrow::after {
  content: "";
  height: 2px;
  flex: 1;
  background: var(--accent);
  opacity: 0.55;
}

h2 {
  font-family: var(--display);
  font-size: clamp(21px, 2.5vw, 30px);
  line-height: 1.32;
  letter-spacing: -0.045em;
  font-weight: 600;
  margin-bottom: 20px;
  max-width: 30ch;
}
h3 {
  font-size: 19px;
  line-height: 1.25;
  letter-spacing: -0.02em;
  font-weight: 600;
  margin-bottom: 8px;
}
h4 {
  font-size: 16px;
  letter-spacing: -0.012em;
  font-weight: 600;
  margin: 0 0 6px;
}

p { max-width: var(--measure); }
p + p { margin-top: 14px; }
.lede { font-size: 20px; line-height: 1.5; letter-spacing: -0.012em; max-width: 46rem; }

.prose > * + * { margin-top: 16px; }
.prose h2 { margin-top: 44px; }
.prose h3 { margin-top: 30px; }
.prose ul { margin-top: 12px; }
.prose li {
  max-width: var(--measure);
  padding-inline-start: 20px;
  position: relative;
}
.prose li + li { margin-top: 8px; }
.prose li::before {
  content: "";
  position: absolute;
  inset-inline-start: 2px;
  top: 0.72em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
.prose a { text-underline-offset: 3px; }

/* --- steps -------------------------------------------------------------- */
.steps { counter-reset: step; margin-top: 26px; display: grid; gap: 22px; }
@media (min-width: 46rem) { .steps { grid-template-columns: repeat(3, 1fr); gap: 32px; } }
.steps li {
  counter-increment: step;
  border-top: 2px solid var(--accent);
  padding-top: 14px;
}
.steps li::before {
  content: counter(step);
  display: block;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text);
  margin-bottom: 6px;
}
.steps p { font-size: 16px; max-width: 36ch; }

/* --- cards -------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 22px;
  --mark-gap: var(--surface);
}
@media (min-width: 60rem) { .card { padding: 26px 28px; } }
.card p, .card li { color: var(--muted); font-size: 16px; }
.card h3, .card h4, .card strong { color: var(--text); }

.modes { display: grid; gap: 18px; margin-top: 28px; }
@media (min-width: 46rem) { .modes { grid-template-columns: 1fr 1fr; } }
@media (min-width: 60rem) { .modes { gap: 22px; } }

.mode-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.mode-head .mark-box { width: 30px; height: 30px; flex: none; }
.mode-head h3 { margin: 0; }

.mode-wide { grid-column: 1 / -1; }
.mode-wide > p { max-width: 52rem; }
.detail { margin-top: 16px; display: grid; gap: 18px 28px; }
@media (min-width: 46rem) { .detail { grid-template-columns: 1fr 1fr; } }
.detail p { font-size: 15px; max-width: 48ch; }

/* MiniShrink is the one place the app speaks in a serif. */
.mode-shrink h3 { font-family: var(--serif); font-size: 22px; font-weight: 600; }

.facts { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 8px; }
.facts + p { margin-top: 14px; }
.facts li {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text);
  border: 1px solid var(--rule);
  border-radius: var(--radius-chip);
  padding: 3px 10px;
}

/* --- claim list ---------------------------------------------------------
   The items sit on --surface rather than on the page, because --muted only
   clears AA against white. See CONTRAST in the README. */
.claims { margin-top: 26px; display: grid; gap: 14px; }
/* Two columns and no more. The lists on this site have four, six and eight
   items, and two columns is the only count that leaves none of them with an
   orphan on the last row. */
@media (min-width: 46rem) { .claims { grid-template-columns: 1fr 1fr; } }
.claims li {
  background: var(--surface);
  border: 1px solid var(--border);
  border-inline-start: 2px solid var(--accent);
  border-radius: var(--radius-tile);
  padding: 14px 18px;
  font-size: 16px;
}
.claims strong { display: block; margin-bottom: 2px; }
.claims span { color: var(--muted); }

/* --- table -------------------------------------------------------------- */
.table-scroll { overflow-x: auto; margin-top: 24px; }
table {
  border-collapse: collapse;
  width: 100%;
  min-width: 32rem;
  font-size: 15px;
}

/* On a phone the requirements table is wider than the screen, and a table you
   have to drag sideways is a table nobody reads. Quantization and context
   length are the two columns a person choosing a phone does not need, so they
   go, and the sentence below the table carries them instead. Scoped to this
   one table: the licence tables have different columns in those positions. */
.narrow-only { display: none; }
@media (max-width: 40rem) {
  .narrow-only { display: block; font-size: 15px; margin-top: 16px; }
  table.requirements { min-width: 0; }
  table.requirements tr > :nth-child(2),
  table.requirements tr > :nth-child(5) { display: none; }
}
caption { text-align: start; color: var(--text); padding-bottom: 10px; font-size: 15px; }
th, td {
  text-align: start;
  padding: 11px 14px 11px 0;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
thead th {
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom-color: var(--rule);
  white-space: nowrap;
}
td.num { font-family: var(--mono); white-space: nowrap; }

/* --- callouts ----------------------------------------------------------- */
.callout {
  background: var(--surface);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--radius-tile);
  padding: 18px 20px;
  margin-top: 24px;
}
.callout p { color: var(--muted); max-width: 52rem; }
.callout p:first-child { color: var(--text); }
.callout h3 { color: var(--text); }

.callout-danger { border-inline-start-color: var(--danger); }

.note { font-size: 14px; color: var(--muted); }
/* Same sentence, for use directly on the page background. */
.qual { font-size: 14px; font-weight: 400; color: var(--text); }

/* --- footer ------------------------------------------------------------- */
.site-footer {
  border-top: 1px solid var(--border);
  padding-block: 36px 48px;
  margin-top: 8px;
}
.site-footer .wrap { display: grid; gap: 18px; }
.footer-nav { display: flex; flex-wrap: wrap; gap: 18px; }
.footer-nav a { font-size: 15px; }
.site-footer p { font-size: 15px; color: var(--text); max-width: 52rem; }

/* --- small utilities ----------------------------------------------------
   Classes rather than style="" attributes, so the Content-Security-Policy
   can say style-src 'self' with no 'unsafe-inline' anywhere. */
.flush { margin-top: 0; }
.spaced { margin-top: 22px; }
.address { font-size: 19px; }

/* --- misc --------------------------------------------------------------- */
code, .mono { font-family: var(--mono); font-size: 0.92em; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ==========================================================================
   Device panels.

   Lifted from Issistant/design/mockups-v2.html: pure HTML and CSS, no images,
   so they stay sharp at any size and cost zero extra requests. The palettes
   below are the same values as src/ui/tokens.ts, which is the whole reason
   they can be trusted as a picture of the app.

   Everything is scoped under .device and the classes are prefixed dv-, because
   the mockup's names (.mark, .content, .chip, .card) collide with this site's.
   In particular an unscoped .mark circle { stroke: var(--text) } would have
   overridden the panels' hardcoded per-mode strokes and killed the one thing
   they are here to show.

   The panels are aria-hidden. They are decoration: every claim they make is
   written out in the text beside them.
   ========================================================================== */

.device {
  --dv-scale: 0.62;
  width: calc(340px * var(--dv-scale));
  height: calc(710px * var(--dv-scale));
  flex: none;
  pointer-events: none;
  user-select: none;
}
.device .dv-phone { transform: scale(var(--dv-scale)); transform-origin: top left; }

/* --- the frame ---------------------------------------------------------- */
.dv-phone {
  width: 340px;
  height: 710px;
  border-radius: 44px;
  overflow: hidden;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45), 0 0 0 10px #111, 0 0 0 12px #333;
  display: flex;
  flex-direction: column;
  position: relative;
  background: var(--dv-bg);
  color: var(--dv-text);
  font-family: var(--sans);
  letter-spacing: normal;
}
.dv-phone * { box-sizing: border-box; }

/* Palettes, from tokens.ts. Only the ones the site actually shows. */
.dv-assistant {
  --dv-bg: #101116; --dv-surface: #1B1D24; --dv-surface2: #23252E; --dv-text: #ECEDF1;
  --dv-muted: #9A9CA6; --dv-faint: #5E606A; --dv-accent: #7D96F5; --dv-accent-soft: #26304F;
  --dv-on-accent: #0E1013; --dv-border: rgba(236, 237, 241, 0.08);
}
.dv-kid {
  --dv-bg: #FFF6E9; --dv-surface: #FFFFFF; --dv-surface2: #FFEDD3; --dv-text: #3A2E22;
  --dv-muted: #8C7A64; --dv-faint: #BCAD97; --dv-accent: #F4772E; --dv-accent-soft: #FFE3C7;
  --dv-on-accent: #FFFFFF; --dv-border: rgba(58, 46, 34, 0.09);
}
.dv-shrink {
  --dv-bg: #141618; --dv-surface: #1D2023; --dv-surface2: #262A2D; --dv-text: #E4E7E3;
  --dv-muted: #969A93; --dv-faint: #5C605A; --dv-accent: #8FB29B; --dv-accent-soft: #26332B;
  --dv-on-accent: #10140F; --dv-border: rgba(228, 231, 227, 0.08);
}

.dv-island {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
  width: 96px; height: 26px; border-radius: 14px; background: #000;
}
.dv-statusbar {
  height: 44px; flex: none; display: flex; align-items: center;
  justify-content: space-between; padding: 0 26px;
  font-size: 13px; font-weight: 600; position: relative; z-index: 5;
}
.dv-bars { display: flex; gap: 3px; align-items: flex-end; }
.dv-bars i { display: block; width: 3px; background: currentColor; border-radius: 1px; }
.dv-bars i:nth-child(1) { height: 5px; }
.dv-bars i:nth-child(2) { height: 8px; }
.dv-bars i:nth-child(3) { height: 11px; }
.dv-batt {
  width: 22px; height: 11px; border: 1.5px solid currentColor; border-radius: 3px;
  position: relative; margin-left: 6px;
}
.dv-batt::after {
  content: ""; position: absolute; inset: 1.5px; right: 6px; background: currentColor; border-radius: 1px;
}

.dv-header { flex: none; display: flex; align-items: center; gap: 9px; padding: 8px 18px 12px; }
.dv-header .dv-title { font-size: 21px; font-weight: 800; letter-spacing: 0.13em; flex: 1; }
.dv-header .dv-title.dv-modename { font-size: 17px; font-weight: 700; letter-spacing: -0.01em; }
.dv-header .dv-title.dv-serif { font-family: var(--serif); font-size: 19px; font-weight: 600; letter-spacing: 0; }
.dv-back { font-size: 20px; color: var(--dv-accent); width: 20px; }
.dv-mark { flex: none; display: block; }
.dv-content { flex: 1; overflow: hidden; display: flex; flex-direction: column; padding: 0 14px; }

.dv-bubbles { flex: 1; display: flex; flex-direction: column; gap: 10px; padding: 8px 4px; overflow: hidden; }
.dv-b { max-width: 82%; padding: 10px 14px; font-size: 14.5px; line-height: 1.42; border-radius: 18px; }
.dv-b.dv-user { align-self: flex-end; background: var(--dv-accent); color: var(--dv-on-accent); border-bottom-right-radius: 6px; }
.dv-b.dv-ai { align-self: flex-start; background: var(--dv-surface); border: 1px solid var(--dv-border); border-bottom-left-radius: 6px; }
.dv-b.dv-ai strong { font-weight: 650; }
.dv-b.dv-ai code { font-family: var(--mono); font-size: 12.5px; background: var(--dv-surface2); border-radius: 5px; padding: 1px 5px; }
.dv-daymark { align-self: center; font-size: 11px; color: var(--dv-faint); font-weight: 500; margin: 2px 0; }
.dv-composer { flex: none; display: flex; gap: 8px; align-items: flex-end; padding: 10px 4px 26px; }
.dv-input {
  flex: 1; background: var(--dv-surface); border: 1px solid var(--dv-border);
  border-radius: 22px; padding: 12px 16px; font-size: 14px; color: var(--dv-faint);
}
.dv-send {
  width: 42px; height: 42px; border-radius: 21px; background: var(--dv-accent);
  color: var(--dv-on-accent); display: flex; align-items: center; justify-content: center; font-size: 17px;
}
.dv-chiprow { display: flex; gap: 8px; padding: 4px 4px 2px; }
.dv-chip {
  border-radius: 999px; border: 1px solid var(--dv-border); background: var(--dv-surface);
  padding: 7px 13px; font-size: 12.5px; font-weight: 600; color: var(--dv-muted);
}
.dv-statusline { font-size: 10.5px; color: var(--dv-faint); padding: 0 8px 6px; }

/* kid-safe: rounder bubbles and the locked band, per shapeFor() in tokens.ts */
.dv-kid .dv-b { border-radius: 24px; font-size: 15.5px; padding: 12px 16px; }
.dv-kid .dv-b.dv-user { border-bottom-right-radius: 8px; }
.dv-kid .dv-b.dv-ai { border-bottom-left-radius: 8px; }
.dv-kid .dv-input { border-radius: 26px; }
.dv-band {
  flex: none; margin: 0 14px 8px; border-radius: 14px; background: var(--dv-accent-soft);
  color: var(--dv-accent); padding: 9px 14px; display: flex; align-items: center;
  gap: 8px; font-size: 13px; font-weight: 700;
}
.dv-band .dv-age { margin-left: auto; font-weight: 600; font-size: 12px; opacity: 0.85; }
.dv-exit { text-align: center; font-size: 12px; color: var(--dv-faint); font-weight: 600; padding-bottom: 4px; }

/* MiniShrink: the user's turn is a neutral card, the assistant has no bubble
   at all. Both are real — see MessageBubble.tsx, `plainAssistant`. */
.dv-shrink .dv-b { border-radius: 16px; line-height: 1.5; }
.dv-shrink .dv-b.dv-user { background: var(--dv-surface2); color: var(--dv-text); border-bottom-right-radius: 5px; }
.dv-shrink .dv-b.dv-ai { background: transparent; border: none; padding-left: 2px; max-width: 92%; color: var(--dv-text); }
.dv-help { background: var(--dv-accent-soft); color: var(--dv-accent); border-radius: 999px; padding: 6px 12px; font-size: 12px; font-weight: 700; }
.dv-breath {
  align-self: center; text-align: center; color: var(--dv-muted); font-size: 13px;
  font-family: var(--serif); font-style: italic; padding: 6px 20px;
}

/* --- the conversation list (hero panel) --------------------------------- */
.dv-iconbtn {
  width: 34px; height: 34px; border-radius: 17px; background: var(--dv-surface2);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; color: var(--dv-muted); flex: none;
}
.dv-pill {
  display: inline-flex; align-items: center; border-radius: 999px;
  padding: 6px 12px; font-size: 12.5px; font-weight: 600;
  background: var(--dv-accent-soft); color: var(--dv-accent);
}
.dv-pillrow { padding: 2px 2px 12px; }
.dv-convo {
  background: var(--dv-surface); border-radius: 16px; padding: 13px 15px;
  margin-bottom: 9px; border: 1px solid var(--dv-border);
}
/* One line, truncated, with the badge beside it and the time pushed right:
   cardTitleLine in app/index.tsx is a row and the title is numberOfLines={1}.
   A wrapping title with the badge dropped underneath is not what it does. */
.dv-convo .dv-top { display: flex; align-items: baseline; margin-bottom: 3px; gap: 6px; }
.dv-convo .dv-name {
  font-size: 15px; font-weight: 600; letter-spacing: -0.01em;
  flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dv-convo .dv-time { font-size: 11.5px; color: var(--dv-faint); flex: none; margin-left: auto; }
.dv-convo .dv-snippet {
  font-size: 13px; color: var(--dv-muted); line-height: 1.35;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.dv-badge {
  display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.04em;
  padding: 2px 7px; border-radius: 6px; background: var(--dv-accent-soft);
  color: var(--dv-accent); vertical-align: 1px; flex: none;
}
.dv-fab {
  position: absolute; bottom: 30px; inset-inline-end: 22px;
  width: 54px; height: 54px; border-radius: 27px;
  background: var(--dv-accent); color: var(--dv-on-accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 26px; font-weight: 300; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
}

/* --- placement ---------------------------------------------------------- */

/* Panels are the first thing to drop. A phone showing a picture of a phone is
   noise, and the copy says everything the picture does. */
.device, .hero-device { display: none; }

@media (min-width: 1100px) {
  .device { display: block; }

  /* Whole, upright, and inside the viewport. It sits on the same right-hand
     gutter as the page content, and the hero is given enough height that the
     frame never reaches an edge — a phone clipped by the fold or the window
     reads as a layout bug, not as a bleed. */
  /* The hero takes the window, so the frame has room to be the size of the
     wordmark rather than a thumbnail beside it. */
  .hero { position: relative; min-height: min(840px, calc(100vh - 90px)); }
  /* Centred in its own zone rather than pinned to the gutter. The zone is
     what is left of the hero once the copy has taken its column: it starts
     where the text measure ends (--measure, 42rem) and runs to the right
     edge, so the midpoint is (100% + 42rem) / 2. Anchoring to the gutter
     instead left the frame hugging the window edge with all the empty space
     pooled between it and the headline. */
  .hero-device {
    display: block;
    position: absolute;
    top: 50%;
    inset-inline-start: calc((100% + var(--measure)) / 2);
    transform: translate(-50%, -50%);
    z-index: 0;
    animation: dv-fade 0.7s ease-out both;
  }
  /* Bounded by both axes: --dv-w grows it with the width, --dv-h is the cap
     the window's height allows, and the smaller wins. Two stepped variables
     rather than one calc() because a scale factor has to be a unitless
     number, and (100vw - 700px)/900 is a *length* — CSS will not divide one
     length by another to give a ratio. Written that way the declaration is
     invalid, --dv-scale falls back to nothing, transform: scale() is dropped,
     and the frame renders at its full 340x710. That is not a subtle failure:
     it is how this panel ended up overlapping the headline. */
  .hero-device .device {
    --dv-w: 0.62;
    --dv-h: 0.6;
    --dv-scale: min(var(--dv-w), var(--dv-h));
  }
  @media (min-width: 1300px) { .hero-device .device { --dv-w: 0.72; } }
  @media (min-width: 1500px) { .hero-device .device { --dv-w: 0.82; } }
  @media (min-width: 1750px) { .hero-device .device { --dv-w: 0.97; } }

  /* 710px of frame plus breathing room has to fit inside min(840px, 100vh-90). */
  @media (min-height: 700px) { .hero-device .device { --dv-h: 0.7; } }
  @media (min-height: 780px) { .hero-device .device { --dv-h: 0.82; } }
  @media (min-height: 860px) { .hero-device .device { --dv-h: 0.97; } }
  .hero .wrap { position: relative; z-index: 1; }

  /* One column, so every mode can put its description beside its panel. */
  .modes { grid-template-columns: 1fr; }
  /* Two cells, not a spanning item across auto rows: a panel spanning every
     row forces those rows to grow to fit it, and the copy drifts apart down
     the card. The text lives in .mode-body so the grid has exactly two
     children and the panel can simply sit beside them. */
  .card.has-device {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: clamp(32px, 4vw, 64px);
    align-items: center;
  }
  .card.has-device .detail { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1440px) {
  .device { --dv-scale: 0.68; }
}

@keyframes dv-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
