/*
 * Alaska's visual language on the web.
 *
 * Two authorities, in this order. The approved artwork
 * (`design/approved/alaska-approved-ui.png`) is what the product looks like;
 * the owner's prototype baseline is the palette and the scale it is expressed
 * in. Where the two were in tension the artwork was sampled and the closer
 * reading won — the measurements, and the one decision they forced, are in
 * `docs/palette-audit.md`.
 *
 * Everything below is a token or a primitive built from tokens. A screen
 * composes them and never re-decides what Alaska's blue is, how far apart two
 * things sit, or how round a card is. That is the whole point: six screens each
 * inventing "a white rounded card with a soft shadow" is how an implementation
 * drifts away from the design it was drawn from.
 *
 * The one thing the web adds is the second layout. The artwork is a phone, and
 * a phone's screen IS its layout: one column, a bottom tab bar. A desktop
 * browser is not a wide phone, so above 900px the tab bar becomes a rail and
 * the column keeps its measure instead of stretching.
 */

/* ═══════════════════════════════════════════════════════════════ tokens ══ */

:root {
  /* ── Colour ────────────────────────────────────────────────────────────
   * The approved baseline. No brand colour exists outside this block, and
   * `scripts/lint.ts` fails the build on any hex that is not one of them. */
  --ink: #171818;
  --muted: #68696b;
  --subtle: #909195;
  --line: #e8eaf2;
  --surface: #ffffff;
  --canvas: #f6f8ff;

  --blue: #4081fe;
  --violet: #8f72fe;
  --pink: #f474c4;
  --mint: #98e1cd;
  /* Success has two values because it has two jobs. `--mint` is a tint and
   * cannot carry a glyph (1.6:1 on white); this is the check the approved
   * artwork actually draws, sampled from it. See docs/palette-audit.md. */
  --mint-ink: #2dc08c;

  /*
   * The reading weights of the same colours.
   *
   * The approved accents were read off artwork, not off a contrast table, and
   * three of them do not carry text on white: blue is 3.63:1, mint-ink 2.33,
   * subtle 3.15 — all under the 4.5 a 14px label needs. These are the same
   * hues mixed toward the ink until they clear it, which is a weight of one
   * colour rather than a second colour. Nothing here is new brand.
   *
   *   --blue-ink  5.14:1 on white, 4.84 on canvas  (links, blue labels)
   *   --pink-deep 5.47:1 on white, 5.16 on canvas  (attention text, danger)
   *   --mint-deep 3.00:1 on white   (the check inside a filled box)
   *
   * The mixes are set by measurement, not taste: the QA pass reads the
   * rendered colour and fails under 4.5, so these carry a margin over it on
   * both surfaces text actually sits on.
   */
  --blue-ink: color-mix(in srgb, var(--blue) 78%, var(--ink));
  /* The checkbox fill keeps the lighter 86% mix: a white glyph needs 3:1,
   * not 4.5, and the brighter tone is closer to the approved artwork. */
  --pink-fill: color-mix(in srgb, var(--pink) 86%, var(--ink));
  --mint-deep: color-mix(in srgb, var(--mint-ink) 86%, var(--ink));
  --pink-deep: color-mix(in srgb, var(--pink) 60%, var(--ink));

  /* Surfaces derived from the palette rather than chosen. `color-mix` keeps
   * them provably on-palette: a tint of a brand colour is not a new colour. */
  --surface-sunken: color-mix(in srgb, var(--canvas) 60%, var(--line));
  --tint-blue: color-mix(in srgb, var(--blue) 10%, transparent);
  --tint-violet: color-mix(in srgb, var(--violet) 10%, transparent);
  --tint-pink: color-mix(in srgb, var(--pink) 12%, transparent);
  --tint-mint: color-mix(in srgb, var(--mint) 34%, transparent);
  --tint-muted: color-mix(in srgb, var(--muted) 9%, transparent);

  /* The primary call to action, and the only place the full gradient runs. */
  --gradient-cta: linear-gradient(112deg, #4081fe 0%, #8f72fe 52%, #f474c4 100%);
  /* The person's own speech. The same three stops on the diagonal. */
  --gradient-speech: linear-gradient(135deg, #8f72fe 0%, #f474c4 100%);
  /* Progress. Blue into violet only: progress is not a celebration. */
  --gradient-progress: linear-gradient(90deg, #4081fe 0%, #8f72fe 100%);

  /* ── Space ──────────────────────────────────────────────────────────────
   * One scale, eight steps. A gap that is not on it is a mistake. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;

  /* ── Radius ─────────────────────────────────────────────────────────────
   * Controls, secondary cards, primary cards. Pill is reserved for status:
   * a pill that is not a status reads as one. */
  --radius-control: 14px;
  --radius-card: 18px;
  --radius-card-lg: 24px;
  --radius-pill: 999px;

  /* ── Elevation ──────────────────────────────────────────────────────────
   * Two levels, soft and desaturated. The cards separate from the canvas by
   * being white on lavender; the shadow only stops the edge looking cut out. */
  --shadow-1: 0 1px 2px rgba(23, 24, 24, 0.04), 0 4px 12px rgba(23, 24, 24, 0.04);
  --shadow-2: 0 2px 6px rgba(23, 24, 24, 0.05), 0 12px 32px rgba(23, 24, 24, 0.07);

  /* ── Type ───────────────────────────────────────────────────────────────
   * The system face, split the way Apple splits it: Display for the sizes
   * that are set tight, Text for everything read in paragraphs. No web font
   * is loaded, so nothing here waits on a network. */
  --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", sans-serif;
  --font-text: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;

  /* Weights the system face actually has. Anything between them is
   * synthesised or silently rounded, so only these five are used. */
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-heavy: 800;

  --text-hero: clamp(48px, 5.2vw, 72px);
  --text-page: clamp(32px, 4vw, 44px);
  --text-h2: clamp(24px, 2.4vw, 32px);
  --text-h3: 20px;
  --text-body: 16px;
  --text-secondary: 14px;
  --text-meta: 12px;

  /* How wide a paragraph may get before it stops being readable. */
  --measure: 64ch;

  /* ── Controls ───────────────────────────────────────────────────────────
   * 44px is the floor every target has to clear; the primary control is
   * taller because the artwork draws it that way. */
  --target-min: 44px;
  --control-height: 52px;

  --rail-width: 248px;
  --tabbar-height: 64px;
  --navbar-height: 56px;

  --ease: cubic-bezier(0.32, 0.72, 0, 1);
}

/*
 * One appearance, deliberately.
 *
 * The palette is not adaptive: the surfaces are white and the ink is
 * near-black, both read off an approved light reference. `color-scheme: light`
 * stops the browser flipping the parts it draws itself — form controls,
 * scrollbars, the caret — around a design that has no dark half. The same
 * decision `AppearanceLock` makes on iOS, for the same reason.
 */
html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
}

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

body {
  margin: 0;
  font-family: var(--font-text);
  font-size: var(--text-body);
  line-height: 1.6;
  font-weight: var(--weight-regular);
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Nothing in this product is a wide page: content that cannot fit scrolls
   * inside its own container, and the page itself never pans sideways. */
  overflow-x: hidden;
}

button,
input,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
}

a {
  color: var(--blue-ink);
  text-decoration: none;
}

img {
  max-width: 100%;
}

/*
 * One focus ring, everywhere.
 *
 * `:focus-visible` rather than `:focus`, so a pointer press does not leave a
 * ring behind while a keyboard press always does. Drawn with a shadow rather
 * than an outline so it follows the radius of whatever it lands on.
 */
:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px var(--surface),
    0 0 0 4px var(--blue);
  border-radius: var(--radius-control);
}

/*
 * `hidden` must actually hide.
 *
 * The attribute's `display: none` comes from the UA stylesheet, and every
 * layout class here sets `display` — so a hidden flex column stayed on screen.
 * It showed up as the "cosa vuoi cambiare" field being visible on a checkpoint
 * that had not offered it.
 */
[hidden] {
  display: none !important;
}

/* ══════════════════════════════════════════════════════════════════ type ══ */

.display,
.title,
.section-title,
.metric {
  font-family: var(--font-display);
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}

/* The one thing on a landing screen. Set as tight as the face allows. */
.hero {
  font-family: var(--font-display);
  font-size: var(--text-hero);
  line-height: 0.99;
  letter-spacing: -0.045em;
  font-weight: var(--weight-heavy);
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}

.display {
  font-size: var(--text-page);
  line-height: 1.06;
  letter-spacing: -0.032em;
  font-weight: var(--weight-bold);
}

.title {
  font-size: var(--text-h2);
  line-height: 1.15;
  letter-spacing: -0.024em;
  font-weight: var(--weight-bold);
}

.section-title {
  font-size: var(--text-h3);
  line-height: 1.25;
  letter-spacing: -0.014em;
  font-weight: var(--weight-semibold);
}

.body {
  font-size: var(--text-body);
  line-height: 1.6;
  margin: 0;
}

.body-strong {
  font-size: var(--text-body);
  line-height: 1.5;
  font-weight: var(--weight-semibold);
  letter-spacing: -0.006em;
  margin: 0;
}

.caption {
  font-size: var(--text-secondary);
  line-height: 1.5;
  color: var(--muted);
  margin: 0;
}

.caption-strong {
  font-size: var(--text-secondary);
  line-height: 1.5;
  font-weight: var(--weight-semibold);
  color: var(--ink);
  margin: 0;
}

/* Metadata and status labels. The floor is 12px, and the only uppercase in
 * the product lives here — never on a heading or a sentence. */
/* `--subtle` is a hairline and a placeholder colour, not a text colour: it is
 * 3.15:1 on white, under what a 12px label needs. Metadata reads in `--muted`,
 * which clears 5.5:1, and `--subtle` keeps the jobs where contrast is not the
 * question — a chevron, a bullet, an empty ring. */
.meta {
  font-size: var(--text-meta);
  line-height: 1.4;
  color: var(--muted);
  margin: 0;
}

.eyebrow {
  font-size: var(--text-meta);
  line-height: 1.4;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

.metric {
  font-size: clamp(36px, 4.4vw, 44px);
  line-height: 1;
  letter-spacing: -0.04em;
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

.muted { color: var(--muted); }
.center { text-align: center; }

/* Paragraphs stop at a readable measure instead of running the width of a
 * desktop card. Centred blocks keep it centred. */
.measure { max-width: var(--measure); }
.center.measure { margin-inline: auto; }

/* ════════════════════════════════════════════════════════════════ layout ══ */

.stack { display: flex; flex-direction: column; min-width: 0; }
.stack-4 { gap: var(--space-1); }
.stack-8 { gap: var(--space-2); }
.stack-12 { gap: var(--space-3); }
.stack-16 { gap: var(--space-4); }
.stack-24 { gap: var(--space-5); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.inline { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }

.app-root {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.boot,
.noscript {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 70vh;
  padding: var(--space-5);
  text-align: center;
  color: var(--muted);
}

.boot-label { font-size: var(--text-secondary); }

/* The page wash. The artwork does not use one flat background everywhere: work
 * in progress sits on cool blue, a screen that needs the person sits on warm
 * pink, success is celebratory. The colour carries the state before any text
 * is read, so it is part of the design rather than decoration — and it is
 * never the only carrier, because colour alone is not a signal. */
.wash-calm { background: var(--canvas); }
.wash-building {
  background: linear-gradient(180deg, var(--canvas) 0%, color-mix(in srgb, var(--blue) 14%, var(--canvas)) 100%);
}
.wash-needsYou {
  background: linear-gradient(180deg, var(--canvas) 0%, color-mix(in srgb, var(--pink) 16%, var(--canvas)) 100%);
}
.wash-celebration {
  background: linear-gradient(180deg, var(--canvas) 0%, color-mix(in srgb, var(--violet) 12%, var(--canvas)) 100%);
}

.shell {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 100vh;
  min-height: 100dvh;
}

.shell-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-bottom: calc(var(--tabbar-height) + env(safe-area-inset-bottom, 0px));
}

.screen {
  flex: 1;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: 0 var(--space-5) var(--space-7);
  min-width: 0;
}

.screen-wide { max-width: 960px; }

/* ═══════════════════════════════════════════════════════════ navigation ══ */

/*
 * The overlaid bars are the one place blur earns its keep: content scrolls
 * under them and the blur is what keeps the title legible over it. Everywhere
 * else the surfaces are solid — an operating screen has to be read, not
 * admired.
 */
.navbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--navbar-height);
  margin: 0 calc(var(--space-5) * -1);
  padding: var(--space-2) var(--space-5);
  padding-top: calc(var(--space-2) + env(safe-area-inset-top, 0px));
  background: color-mix(in srgb, var(--canvas) 82%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
}

.navbar-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: var(--weight-semibold);
  letter-spacing: -0.012em;
  color: var(--ink);
  min-width: 0;
}

.navbar-title span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.navbar-spacer { flex: 1; }

/* Every tap target clears 44×44, whatever the glyph inside it measures. */
.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--target-min);
  height: var(--target-min);
  flex: none;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink);
  transition: background-color 0.15s var(--ease);
}

.icon-button:hover { background: var(--tint-muted); }
.icon-button:active { background: color-mix(in srgb, var(--muted) 16%, transparent); }

.icon-button-accent {
  background: var(--gradient-cta);
  color: var(--surface);
  box-shadow: var(--shadow-1);
}

.icon-button-accent:hover {
  background: var(--gradient-cta);
  filter: brightness(1.05);
}

.icon-button-accent:active { filter: brightness(0.96); }

.wordmark { display: flex; align-items: center; gap: var(--space-3); }

.wordmark-text {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.14em;
  color: var(--blue-ink);
}

.mark { border-radius: var(--radius-pill); display: block; flex: none; }
.mark-square { border-radius: var(--radius-control); }

/* The bottom bar: a solid white plate, a hairline above it, and the selected
 * item named in blue. Hand-built, exactly as the artwork draws it. */
.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

.tabbar-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-1);
  border: 0;
  background: none;
  color: var(--subtle);
  font-size: var(--text-meta);
  line-height: 1.4;
  font-weight: var(--weight-semibold);
  position: relative;
  transition: color 0.15s var(--ease);
}

.tabbar-item[aria-current="page"] { color: var(--blue-ink); }

.tabbar-badge,
.rail-badge {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--pink);
  color: var(--surface);
  font-size: var(--text-meta);
  line-height: 18px;
  font-weight: var(--weight-semibold);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.tabbar-badge {
  position: absolute;
  top: var(--space-1);
  left: calc(50% + 6px);
}

.rail { display: none; }

/* ═════════════════════════════════════════════════════════════ surfaces ══ */

/* The primary card: what a screen is mostly made of. */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card-lg);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
}

/* A card whose rows manage their own padding and dividers. */
.list-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}

.card-quiet {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  box-shadow: none;
  padding: var(--space-4);
}

.row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: var(--target-min);
  padding: var(--space-4) var(--space-5);
  border: 0;
  background: none;
  text-align: left;
  color: inherit;
  transition: background-color 0.15s var(--ease);
}

button.row:hover { background: var(--surface-sunken); }
button.row:active { background: var(--tint-muted); }

.row + .row { border-top: 1px solid var(--line); }
.row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }

.row-title {
  font-size: var(--text-body);
  line-height: 1.4;
  font-weight: var(--weight-medium);
  color: var(--ink);
}

.row-detail {
  font-size: var(--text-secondary);
  line-height: 1.5;
  color: var(--muted);
}

.chevron { color: var(--subtle); flex: none; display: inline-flex; }

/* ══════════════════════════════════════════════════════════════ controls ══ */

/*
 * The primary action: a full-width gradient pill.
 *
 * Not a system button with a tint — the artwork's button is a three-stop
 * gradient with its own height and radius, and no system style bends into it.
 * The gradient appears here, on selected accents, and on progress. Nowhere
 * else: a gradient on everything is a gradient on nothing.
 */
.button-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--control-height);
  padding: 0 var(--space-5);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--gradient-cta);
  color: var(--surface);
  font-family: var(--font-text);
  font-size: var(--text-secondary);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.004em;
  box-shadow: 0 6px 16px color-mix(in srgb, var(--violet) 30%, transparent);
  transition: transform 0.15s var(--ease), box-shadow 0.15s var(--ease), filter 0.15s var(--ease);
}

.button-primary:hover:not(:disabled) {
  filter: brightness(1.04);
  box-shadow: 0 8px 22px color-mix(in srgb, var(--violet) 34%, transparent);
}

.button-primary:active:not(:disabled) {
  transform: translateY(1px);
  filter: brightness(0.97);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--violet) 26%, transparent);
}

/* Unavailable is a different fill, not a fainter one: a saturated gradient at
 * 45% opacity still reads as enabled and simply does not work. */
.button-primary:disabled {
  background: var(--surface-sunken);
  color: var(--subtle);
  box-shadow: none;
  cursor: default;
}

.button-outline {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--target-min);
  padding: 0 var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--blue-ink);
  font-size: var(--text-secondary);
  font-weight: var(--weight-semibold);
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.button-outline:hover:not(:disabled) {
  background: var(--tint-blue);
  border-color: color-mix(in srgb, var(--blue) 32%, var(--line));
}

.button-outline:active:not(:disabled) { background: color-mix(in srgb, var(--blue) 16%, transparent); }

.button-outline:disabled { color: var(--subtle); cursor: default; }

.button-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--blue-ink);
  font-size: var(--text-secondary);
  font-weight: var(--weight-semibold);
  transition: background-color 0.15s var(--ease);
}

.button-link:hover { background: var(--tint-blue); }

.button-quiet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-control);
  background: none;
  color: var(--muted);
  font-size: var(--text-secondary);
  font-weight: var(--weight-medium);
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}

.button-quiet:hover { background: var(--tint-muted); color: var(--ink); }

/* The destructive action reads in the ink weight of pink: the tint itself is
 * 2.58:1 on white, which is not a colour a word may be written in. */
.button-danger { color: var(--pink-deep); }
.button-danger:hover { background: var(--tint-pink); color: var(--pink-deep); }

/* ════════════════════════════════════════════════════════════════ status ══ */

/*
 * A state, as a small pill.
 *
 * Label, glyph and colour come from one lookup, so they cannot disagree — and
 * the glyph is why this is not colour alone. Working, waiting and needs-you
 * are distinguishable with the colour removed, which is the only way a status
 * is legible to somebody who cannot separate blue from pink.
 */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 5px var(--space-3) 5px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-meta);
  line-height: 1.4;
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}

.pill svg { flex: none; }

.tone-idle { color: var(--muted); background: var(--tint-muted); }
.tone-working { color: var(--blue-ink); background: var(--tint-blue); }
.tone-attention { color: var(--pink-deep); background: var(--tint-pink); }
.tone-problem { color: var(--pink-deep); background: var(--tint-pink); }
.tone-good { color: var(--mint-deep); background: var(--tint-mint); }

.badge-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  border-radius: var(--radius-control);
}

/* The dot beside an app that wants somebody. Never the only signal — the row
 * also carries its state pill — but the one that survives a glance. */
.attention-dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: var(--radius-pill);
  background: var(--pink);
}

/* ══════════════════════════════════════════════════════════════════ chat ══ */

.chat {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) 0 var(--space-5);
}

.bubble-line { display: flex; align-items: flex-end; gap: var(--space-2); }
.bubble-line.from-user { justify-content: flex-end; padding-left: var(--space-7); }
.bubble-line.from-alaska { padding-right: var(--space-7); }

.bubble {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-card);
  font-size: var(--text-body);
  line-height: 1.55;
  max-width: var(--measure);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.bubble-user {
  background: var(--gradient-speech);
  color: var(--surface);
  border-bottom-right-radius: var(--space-1);
}

.bubble-alaska {
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
  border-bottom-left-radius: var(--space-1);
}

.composer {
  position: sticky;
  bottom: 0;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
  margin: 0 calc(var(--space-5) * -1);
  padding: var(--space-3) var(--space-5) calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  border-top: 1px solid var(--line);
}

/*
 * What the person is typing is never inherited.
 *
 * The iOS composer failed exactly here: a field with no explicit colour drew
 * in the system's primary ink, which flips to white in dark mode, inside a
 * capsule this design hard-codes to white. The web has the same trap through
 * the UA stylesheet, so the field states its own ink, its own placeholder and
 * its own caret.
 */
.composer-field {
  flex: 1;
  min-height: var(--target-min);
  max-height: 140px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink);
  caret-color: var(--blue);
  font-family: var(--font-text);
  font-size: var(--text-body);
  line-height: 1.45;
  resize: none;
  overflow-y: auto;
  transition: border-color 0.15s var(--ease);
}

.composer-field::placeholder { color: var(--subtle); }
.composer-field:focus { border-color: color-mix(in srgb, var(--blue) 40%, var(--line)); }

.composer-send {
  flex: none;
  width: var(--target-min);
  height: var(--target-min);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--gradient-cta);
  color: var(--surface);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: filter 0.15s var(--ease);
}

.composer-send:hover:not(:disabled) { filter: brightness(1.05); }

/* ── Attachments ─────────────────────────────────────────────────────────
 * The paperclip, the tray and its chips. One component for both composers
 * (client/attachments.ts), so one set of rules here. The paperclip mirrors
 * the phone's: a quiet circle to the LEFT of the field, never a gradient —
 * attaching is preparation, not the primary action. */

.composer-attach {
  flex: none;
  width: var(--target-min);
  height: var(--target-min);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s var(--ease), color 0.15s var(--ease);
}

.composer-attach:hover {
  border-color: color-mix(in srgb, var(--blue) 32%, var(--line));
  color: var(--blue-ink);
}

/* Compact, above the composer, solid: the working area owns no glass. */
.attach-tray {
  position: sticky;
  bottom: 0;
  z-index: 10;
  margin: 0 calc(var(--space-5) * -1);
  padding: var(--space-2) var(--space-5);
  background: var(--surface);
  border-top: 1px solid var(--line);
}

/* Chips scroll sideways inside their own strip; the page never does. */
.attach-strip {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  scrollbar-width: none;
}
.attach-strip::-webkit-scrollbar { display: none; }

.attach-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 240px;
  min-height: var(--target-min);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--surface);
}

.attach-failed { border-color: color-mix(in srgb, var(--pink) 45%, var(--line)); }

.attach-thumb {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: var(--surface-sunken);
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.attach-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.attach-words {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.attach-name {
  font-size: var(--text-secondary);
  font-weight: var(--weight-medium);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.attach-state {
  font-size: var(--text-meta);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.attach-failed .attach-state { color: var(--pink-deep); }

/* Upload progress: the track is the chip's own width, the fill is written
 * through the CSSOM as the bytes move. */
.attach-progress {
  display: block;
  width: 120px;
  height: 3px;
  border-radius: var(--radius-pill);
  background: var(--line);
  overflow: hidden;
}

.attach-progress i {
  display: block;
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: var(--gradient-progress);
  transition: width 0.2s var(--ease);
}

/* Remove and retry: full 44px targets, quiet until hovered. */
.attach-action {
  flex: none;
  width: var(--target-min);
  height: var(--target-min);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.attach-action:hover { background: var(--tint-muted); color: var(--ink); }

.attach-problem {
  margin: var(--space-1) 0 0;
  font-size: var(--text-meta);
  color: var(--pink-deep);
}
.attach-problem[hidden] { display: none; }

/* What an old message carried, under its bubble: names, not thumbnails —
 * the turn records filenames and honesty beats decoration. */
.sent-files {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  justify-content: flex-end;
  max-width: min(78%, 520px);
}

.sent-file {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 3px var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-size: var(--text-meta);
  color: var(--muted);
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sent-file svg { flex: none; }

/* A file over the conversation: the whole screen says it will take it. */
.screen.dropping::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  border: 2px dashed color-mix(in srgb, var(--blue) 55%, transparent);
  border-radius: var(--radius-card);
  background: color-mix(in srgb, var(--blue) 6%, transparent);
}

.composer-send:disabled {
  background: var(--surface-sunken);
  color: var(--subtle);
  cursor: default;
}

.thinking {
  display: inline-flex;
  gap: var(--space-1);
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  border-bottom-left-radius: var(--space-1);
}

.thinking i {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  background: var(--subtle);
  animation: pulse 1.2s infinite ease-in-out;
}

.thinking i:nth-child(2) { animation-delay: 0.15s; }
.thinking i:nth-child(3) { animation-delay: 0.3s; }

@keyframes pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

/* ════════════════════════════════════════════════════════════════ inputs ══ */

.field {
  width: 100%;
  min-height: var(--target-min);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--ink);
  caret-color: var(--blue);
  font-family: var(--font-text);
  font-size: var(--text-body);
  line-height: 1.5;
  transition: border-color 0.15s var(--ease);
}

.field::placeholder { color: var(--subtle); }
.field:focus { border-color: color-mix(in srgb, var(--blue) 40%, var(--line)); }

.field-label {
  font-size: var(--text-secondary);
  line-height: 1.5;
  font-weight: var(--weight-semibold);
  color: var(--ink);
}

/* An answer offered as a tap. The person answering is not a developer: the
 * same question offered as two phrases gets answered in one tap. */
.choice {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-size: var(--text-secondary);
  font-weight: var(--weight-medium);
  color: var(--ink);
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.choice:hover { border-color: color-mix(in srgb, var(--blue) 30%, var(--line)); }

.choice[aria-pressed="true"] {
  border-color: transparent;
  background: var(--gradient-speech);
  color: var(--surface);
}

.choices { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ═════════════════════════════════════════════════════════════ checklist ══ */

.checklist-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
}

.checklist-row + .checklist-row { border-top: 1px solid var(--line); }

.checkbox {
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--surface);
}

.checkbox-pending { border: 1.5px solid var(--line); }

.checklist-title {
  flex: 1;
  font-size: var(--text-body);
  line-height: 1.4;
  color: var(--ink);
}

.checklist-title.pending { color: var(--muted); }

.progress-track {
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--line);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--gradient-progress);
  transition: width 0.4s var(--ease);
}

/* ══════════════════════════════════════════════════════════════ pictures ══ */

.app-icon {
  width: 46px;
  height: 46px;
  flex: none;
  border-radius: var(--radius-control);
  object-fit: cover;
  border: 1px solid var(--line);
  background: var(--surface-sunken);
}

/* An app with no icon yet gets its initials on a tint derived from its own
 * name — stable, tells two apps apart, and never pretends to be artwork
 * somebody chose. Alaska's own mountain would say the app belongs to Alaska. */
.app-icon-placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--surface);
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
}

.proposals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-3);
}

.proposal {
  display: block;
  padding: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  text-align: left;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease), transform 0.15s var(--ease);
}

.proposal:hover { box-shadow: var(--shadow-2); transform: translateY(-2px); }

/* Chosen is a ring plus a check, not a colour: a selection carried by hue
 * alone is not a selection everybody can see. */
.proposal[aria-pressed="true"] {
  border-color: var(--violet);
  box-shadow: 0 0 0 1px var(--violet), var(--shadow-2);
}

.proposal img,
.proposal-blank {
  width: 100%;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  border-radius: var(--radius-control);
  background: var(--surface-sunken);
  display: block;
}

.proposal-caption { padding: var(--space-2) var(--space-1) var(--space-1); }

/* ════════════════════════════════════════════════════════════════ states ══ */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);
  padding: var(--space-7) 0;
}

.empty img { width: min(190px, 52vw); height: auto; }
.empty .button-primary { max-width: 320px; }

.loading { display: flex; justify-content: center; padding-top: var(--space-8); }

.spinner {
  width: 26px;
  height: 26px;
  border: 2.5px solid var(--line);
  border-top-color: var(--blue);
  border-radius: var(--radius-pill);
  animation: spin 0.9s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* A skeleton is worth more than a spinner where the shape is already known: it
 * says how much is coming, and the page does not reflow when it does. */
.skeleton {
  height: 76px;
  border-radius: var(--radius-card);
  background: var(--surface-sunken);
  animation: shimmer 1.8s ease-in-out infinite;
}

@keyframes shimmer {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  font-size: var(--text-secondary);
  line-height: 1.5;
}

.banner svg { flex: none; margin-top: 2px; }

.banner-problem {
  background: var(--tint-pink);
  border-color: color-mix(in srgb, var(--pink) 24%, transparent);
  color: color-mix(in srgb, var(--pink) 74%, var(--ink));
}

.banner-info {
  background: var(--tint-blue);
  border-color: color-mix(in srgb, var(--blue) 22%, transparent);
  color: color-mix(in srgb, var(--blue) 78%, var(--ink));
}

.banner-good {
  background: var(--tint-mint);
  border-color: color-mix(in srgb, var(--mint-ink) 24%, transparent);
  color: color-mix(in srgb, var(--mint-ink) 84%, var(--ink));
}

.details {
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--surface);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-secondary);
}

/* The disclosure is a control, so it clears the same floor every other
 * control does. It was 24px tall: a legible line of text, and a target a thumb
 * misses. The negative margin keeps the closed card the size it looks. */
.details summary {
  display: flex;
  align-items: center;
  cursor: pointer;
  color: var(--muted);
  min-height: var(--target-min);
  margin: calc(var(--space-2) * -1) 0;
  font-weight: var(--weight-medium);
  list-style: none;
}

.details summary::-webkit-details-marker { display: none; }

.details summary::after {
  content: "";
  width: 6px;
  height: 6px;
  margin-left: auto;
  border-right: 1.75px solid currentColor;
  border-bottom: 1.75px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s var(--ease);
}

.details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }

.details pre {
  margin: var(--space-2) 0 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-size: var(--text-meta);
  line-height: 1.5;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

.kv {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  font-size: var(--text-secondary);
  line-height: 1.5;
}

.kv + .kv { border-top: 1px solid var(--line); }

.kv-value {
  font-weight: var(--weight-semibold);
  overflow-wrap: anywhere;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* A bullet that is a bullet, not a middot pretending to be one. */
.bullets { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }

.bullets li {
  position: relative;
  padding-left: var(--space-4);
  font-size: var(--text-body);
  line-height: 1.55;
  max-width: var(--measure);
}

.bullets li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--subtle);
}

.bullets-quiet li { font-size: var(--text-secondary); color: var(--muted); }

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--tabbar-height) + var(--space-4) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 60;
  max-width: min(520px, calc(100vw - var(--space-6)));
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-control);
  background: var(--ink);
  color: var(--surface);
  font-size: var(--text-secondary);
  line-height: 1.45;
  box-shadow: var(--shadow-2);
}

.confetti { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.confetti i { position: absolute; width: 8px; height: 12px; border-radius: 2px; opacity: 0.7; }

.celebration-head { position: relative; padding: var(--space-5) 0 var(--space-2); text-align: center; }

/*
 * Motion is decoration here, and decoration is optional.
 *
 * Everything below either loops or moves on its own. A person who has asked
 * the system to stop that has asked for a reason.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ═══════════════════════════════════════════════════════════════ desktop ══ */

@media (min-width: 900px) {
  .shell { flex-direction: row; }

  .shell-body { flex: 1; padding-bottom: 0; }

  .tabbar { display: none; }

  /* The tab bar becomes a rail. Same three destinations, same order, same
   * badge — a desktop browser is not a wide phone, but it is the same
   * product. */
  .rail {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    width: var(--rail-width);
    flex: none;
    padding: var(--space-6) var(--space-4);
    border-right: 1px solid var(--line);
    background: var(--surface);
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100dvh;
  }

  .rail-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: var(--target-min);
    padding: var(--space-3) var(--space-4);
    border: 0;
    border-radius: var(--radius-control);
    background: none;
    color: var(--muted);
    font-size: var(--text-secondary);
    font-weight: var(--weight-semibold);
    text-align: left;
    transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
  }

  .rail-item:hover { background: var(--surface-sunken); color: var(--ink); }

  .rail-item[aria-current="page"] { background: var(--tint-blue); color: var(--blue-ink); }

  .rail-badge { margin-left: auto; }
  .rail-head { padding: 0 var(--space-4) var(--space-6); }
  .rail-foot { margin-top: auto; padding: 0 var(--space-4); }

  /* The operating area is solid: content does not scroll under the header on
   * a desktop, so the blur has nothing to do but soften what should be read. */
  .navbar {
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    padding-top: var(--space-4);
  }

  .screen { padding: 0 var(--space-6) var(--space-8); }
  .card { padding: var(--space-6); }
  .row { padding: var(--space-4) var(--space-6); }
  .checklist-row { padding: var(--space-4) var(--space-6); }
  .composer { margin: 0 calc(var(--space-6) * -1); padding: var(--space-4) var(--space-6); }
  .toast { bottom: var(--space-5); }
}

@media (min-width: 1200px) {
  .screen { max-width: 680px; }
  .screen-wide { max-width: 1040px; }
}

/* ══════════════════════════════════════════════════════════ tone classes ══ */

/*
 * The tones, named once.
 *
 * `components.ts` picks a tone by role — a milestone, a section badge, an app
 * with no icon yet — and the value lives here. That split is what keeps a hex
 * literal out of the TypeScript, which is what `scripts/lint.ts` enforces.
 */
.fill-blue { background: var(--blue); }
.fill-violet { background: var(--violet); }
/* The two tones a white check cannot sit on at full strength: 2.58:1 and
 * 2.33:1. Mixed toward the ink until the glyph reads, which keeps the tone
 * and buys the contrast. */
.fill-pink { background: var(--pink-fill); }
.fill-mint { background: var(--mint-deep); }
.fill-quiet { background: var(--subtle); }

.badge-blue { background: var(--tint-blue); color: var(--blue-ink); }
.badge-violet { background: var(--tint-violet); color: color-mix(in srgb, var(--violet) 88%, var(--ink)); }
.badge-pink { background: var(--tint-pink); color: var(--pink-deep); }
.badge-mint { background: var(--tint-mint); color: var(--mint-deep); }
.badge-quiet { background: var(--tint-muted); color: var(--muted); }

.badge-sm { width: 28px; height: 28px; border-radius: 9px; }

/* An app with no icon yet carries its initials in white, so the tint has to
 * hold them: these run from the tone to a darker weight of the same tone
 * rather than from a pale tint to the tone. */
.placeholder-blue { background: linear-gradient(135deg, var(--blue), color-mix(in srgb, var(--blue) 72%, var(--ink))); }
.placeholder-violet { background: linear-gradient(135deg, var(--violet), color-mix(in srgb, var(--violet) 72%, var(--ink))); }
.placeholder-pink { background: linear-gradient(135deg, var(--pink-deep), color-mix(in srgb, var(--pink) 68%, var(--ink))); }
.placeholder-mint { background: linear-gradient(135deg, var(--mint-deep), color-mix(in srgb, var(--mint-ink) 68%, var(--ink))); }

.metric-accent {
  background: var(--gradient-progress);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.spinner-sm { width: 18px; height: 18px; border-width: 2px; }

/* The trailing mark on a checklist row. Done is a check, not-started is an
 * empty ring: two shapes, so the list survives being read without colour. */
.checklist-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex: none;
}

.checklist-mark.done { color: var(--mint-deep); }

.checklist-mark.pending {
  border: 2px solid var(--line);
  border-radius: var(--radius-pill);
}

/* The steps still to come on the defining screen. Same empty ring the
 * checklist uses for "not started", so the two screens agree about what an
 * unfinished step looks like. */
.upcoming { text-align: left; }

.upcoming-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.upcoming-row .checklist-mark { margin-top: 3px; }
.upcoming-row .body { max-width: var(--measure); }

/* ══════════════════════════════════════════════════════════════ landing ══ */

/*
 * The first thing anybody sees, and the one screen with room to breathe.
 *
 * Blur belongs here and in the overlaid bars, and nowhere else: this screen is
 * being looked at, and the operating screens are being read.
 */
.landing {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);
  padding: var(--space-8) 0 var(--space-7);
}

.landing .hero { margin-top: var(--space-2); }

.landing::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset-inline: 0;
  top: 0;
  height: 420px;
  pointer-events: none;
  background:
    radial-gradient(60% 70% at 50% 0%, color-mix(in srgb, var(--violet) 16%, transparent), transparent 70%),
    radial-gradient(50% 60% at 15% 10%, color-mix(in srgb, var(--blue) 14%, transparent), transparent 70%);
  filter: blur(24px);
}

.screen { position: relative; }

/* The price. Solid ink, not the gradient: a number somebody is about to pay
 * is a fact, and the gradient is reserved for what they can act on. */
.price {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* "1 azione richiesta". An eyebrow, so it reads as the label it is, in the
 * tone of the state it belongs to — and never as a heading. */
.attention-label { color: var(--pink-deep); }

/*
 * A section heading with a badge in front of it.
 *
 * Not `.inline`: that wraps, which is right for a row of chips and wrong here —
 * a heading long enough to wrap dropped underneath its own badge and lost the
 * alignment the artwork gives every one of these rows. The badge holds its
 * column, the words wrap inside theirs, and the two stay on the same first
 * baseline.
 */
.section-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.section-head .section-title { min-width: 0; }
