/*
 * NoteTheBoat — design system.
 *
 * Two aesthetics were deliberately avoided. Violet-gradient-on-near-black is
 * the default look of every AI-generated landing page; warm cream with a serif
 * display face and a terracotta accent has become the second one. Neither says
 * anything true about this product.
 *
 * What is true: NoteTheBoat is a precision instrument for people whose meetings
 * are confidential and multilingual. So the page is typographic and the hero
 * demonstrates per-line language detection instead of describing it.
 *
 * Colour is present but earns its place. Every hue means something — the accent
 * is action and brand, `--ours` is us in a comparison, and the three language
 * hues are languages. The neutrals carry a real blue cast rather than being
 * greyscale, which is what stops the surface reading as unfinished. Nothing is
 * tinted merely to look tinted, and there is not a gradient on the site.
 *
 * Baseline 2026 throughout: cascade layers, native nesting, container queries,
 * :has(), OKLCH, @starting-style, scroll-driven animations, cross-document view
 * transitions, the Popover API. Anchor positioning is used only where a plain
 * fallback exists, since its support is still uneven.
 *
 * One exception, learned the hard way: the theme is NOT built on the newest
 * thing available. `light-dark()` made the palette a single elegant line and
 * made the toggle fail on a real machine while passing every check here. The
 * dark palette is now written out and applied three independent ways — see the
 * tokens layer. A feature the whole site's legibility depends on does not get
 * to be clever.
 *
 * Layout is container-query-driven, not viewport-driven: a card decides its own
 * layout from the space it is actually given, so the same component is correct
 * in a 360px phone and a 1440px grid without a media-query cascade to maintain.
 */

@layer reset, tokens, base, layout, components, utilities;

/* ------------------------------------------------------------------ reset */

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

  * {
    margin: 0;
  }

  html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    interpolate-size: allow-keywords;
  }

  body {
    min-block-size: 100svb;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  img,
  svg,
  video {
    display: block;
    max-inline-size: 100%;
    block-size: auto;
  }

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

  button {
    background: none;
    border: none;
    cursor: pointer;
  }

  :where(ul, ol)[role='list'] {
    list-style: none;
    padding: 0;
  }

  :target {
    scroll-margin-block-start: 6rem;
  }

  :focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 2px;
  }
}

/* ----------------------------------------------------------------- tokens */

@layer tokens {
  :root {
    color-scheme: light;

    /*
     * The neutrals carry a real blue cast (chroma ~0.02) rather than being
     * greyscale. Pure grey is what makes an interface read as unfinished — the
     * tint is what makes the surface look chosen, and it lets the accent sit on
     * it as a member of the same family instead of as a sticker.
     */
    --ink-12: oklch(0.19 0.03 265);
    --ink-11: oklch(0.34 0.03 265);
    --ink-10: oklch(0.48 0.033 265);
    --ink-9: oklch(0.6 0.03 265);
    --ink-6: oklch(0.87 0.018 265);
    --ink-4: oklch(0.93 0.014 265);
    --ink-2: oklch(0.968 0.01 265);
    --ink-1: oklch(0.995 0.004 265);
    --surface: var(--ink-1);
    --surface-raised: var(--ink-2);
    --border: var(--ink-6);
    --border-strong: var(--ink-9);
    --text: var(--ink-12);
    --text-muted: var(--ink-10);
    --text-faint: var(--ink-9);

    /*
     * Two hues carry meaning and nothing else carries any.
     *
     * `--accent` is action and brand: the primary button, links, the wordmark,
     * the checkmarks in a plan. `--ours` is us in a comparison: the NoteTheBoat
     * column, the "included" state. Because both are anchored to the same blue
     * family as the neutrals, the page reads as coloured without any surface
     * needing a gradient on it.
     */
    --accent: oklch(0.52 0.21 255);
    --accent-hover: oklch(0.46 0.22 255);
    --accent-contrast: oklch(0.99 0.005 255);
    --accent-quiet: oklch(0.96 0.032 255);
    --accent-line: oklch(0.86 0.07 255);
    --ours: oklch(0.5 0.13 185);
    --ours-quiet: oklch(0.96 0.035 185);
    --ours-line: oklch(0.85 0.07 185);
    /* Language tags in the transcript. Three hues far enough apart to be told
       apart at 10px, each with a tinted chip so the eye finds them instantly. */
    --lang-he: oklch(0.48 0.17 265);
    --lang-he-bg: oklch(0.95 0.035 265);
    --lang-ar: oklch(0.46 0.13 165);
    --lang-ar-bg: oklch(0.94 0.04 165);
    --lang-en: oklch(0.5 0.15 45);
    --lang-en-bg: oklch(0.955 0.04 55);
    --positive: oklch(0.48 0.14 155);
    --warning: oklch(0.58 0.15 70);
    --danger: oklch(0.53 0.19 25);
    --scrim: oklch(0.2 0 0 / 0.28);
    --shadow-hairline: oklch(0 0 0 / 0.1);
    --shadow-lift: oklch(0 0 0 / 0.25);
    --shadow-tint: oklch(0.5 0.1 265 / 0.06);
    --shadow-tint-far: oklch(0.5 0.15 265 / 0.22);
    --font-sans:
      'Heebo', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

    /* Fluid scale, 360px → 1280px. Ratio tightens as it grows so long Hebrew
       headings do not run away on desktop. */
    --step--1: clamp(0.83rem, 0.8rem + 0.15vi, 0.9rem);
    --step-0: clamp(0.97rem, 0.94rem + 0.16vi, 1.06rem);
    --step-1: clamp(1.13rem, 1.05rem + 0.4vi, 1.35rem);
    --step-2: clamp(1.35rem, 1.18rem + 0.85vi, 1.85rem);
    --step-3: clamp(1.65rem, 1.3rem + 1.75vi, 2.6rem);
    --step-4: clamp(2rem, 1.35rem + 3.25vi, 3.9rem);

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4.5rem;
    --space-9: 7rem;

    --radius-sm: 6px;
    --radius: 10px;
    --radius-lg: 16px;

    --measure: 62ch;
    --gutter: clamp(1.25rem, 4vi, 3rem);
    --page: 1180px;

    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  }

/*
   * The dark palette, applied three independent ways.
   *
   * This used to be one clever line — `light-dark()` inside every token, with
   * `:root:has(#theme-dark:checked)` flipping `color-scheme`. It worked here and
   * did nothing on a real user's machine, and the reason it was impossible to
   * see is that the trick needs three separate modern features to all hold at
   * once. When one did not, the click had no effect and nothing reported an
   * error.
   *
   * So the palette is written out instead of computed:
   *   1. the OS preference, for a visitor who has never chosen;
   *   2. `data-theme` on <html>, which the toggle sets — plain attribute
   *      matching, and the path that actually runs for anyone with JS;
   *   3. `:has()` on the radios, so the switch still works with JS disabled.
   * Any one of them alone is enough. Verbose beats clever for the control that
   * repaints the entire site.
   */
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) {
      color-scheme: dark;
      --ink-12: oklch(0.97 0.008 265);
      --ink-11: oklch(0.89 0.012 265);
      --ink-10: oklch(0.76 0.018 265);
      --ink-9: oklch(0.63 0.022 265);
      --ink-6: oklch(0.35 0.025 265);
      --ink-4: oklch(0.27 0.022 265);
      --ink-2: oklch(0.2 0.018 265);
      --ink-1: oklch(0.16 0.015 265);
      --accent: oklch(0.7 0.18 255);
      --accent-hover: oklch(0.77 0.17 255);
      --accent-contrast: oklch(0.15 0.02 265);
      --accent-quiet: oklch(0.24 0.05 258);
      --accent-line: oklch(0.38 0.08 258);
      --ours: oklch(0.75 0.11 185);
      --ours-quiet: oklch(0.24 0.045 190);
      --ours-line: oklch(0.38 0.07 190);
      --lang-he: oklch(0.76 0.14 265);
      --lang-he-bg: oklch(0.26 0.055 265);
      --lang-ar: oklch(0.76 0.12 165);
      --lang-ar-bg: oklch(0.25 0.05 165);
      --lang-en: oklch(0.78 0.13 55);
      --lang-en-bg: oklch(0.26 0.05 45);
      --positive: oklch(0.76 0.12 155);
      --warning: oklch(0.8 0.14 75);
      --danger: oklch(0.73 0.16 25);
      --scrim: oklch(0 0 0 / 0.6);
      --shadow-hairline: oklch(0 0 0 / 0.4);
      --shadow-lift: oklch(0 0 0 / 0.7);
      --shadow-tint: oklch(0 0 0 / 0.3);
      --shadow-tint-far: oklch(0 0 0 / 0.5);
    }
  }

  :root[data-theme='dark'] {
    color-scheme: dark;
    --ink-12: oklch(0.97 0.008 265);
    --ink-11: oklch(0.89 0.012 265);
    --ink-10: oklch(0.76 0.018 265);
    --ink-9: oklch(0.63 0.022 265);
    --ink-6: oklch(0.35 0.025 265);
    --ink-4: oklch(0.27 0.022 265);
    --ink-2: oklch(0.2 0.018 265);
    --ink-1: oklch(0.16 0.015 265);
    --accent: oklch(0.7 0.18 255);
    --accent-hover: oklch(0.77 0.17 255);
    --accent-contrast: oklch(0.15 0.02 265);
    --accent-quiet: oklch(0.24 0.05 258);
    --accent-line: oklch(0.38 0.08 258);
    --ours: oklch(0.75 0.11 185);
    --ours-quiet: oklch(0.24 0.045 190);
    --ours-line: oklch(0.38 0.07 190);
    --lang-he: oklch(0.76 0.14 265);
    --lang-he-bg: oklch(0.26 0.055 265);
    --lang-ar: oklch(0.76 0.12 165);
    --lang-ar-bg: oklch(0.25 0.05 165);
    --lang-en: oklch(0.78 0.13 55);
    --lang-en-bg: oklch(0.26 0.05 45);
    --positive: oklch(0.76 0.12 155);
    --warning: oklch(0.8 0.14 75);
    --danger: oklch(0.73 0.16 25);
    --scrim: oklch(0 0 0 / 0.6);
    --shadow-hairline: oklch(0 0 0 / 0.4);
    --shadow-lift: oklch(0 0 0 / 0.7);
    --shadow-tint: oklch(0 0 0 / 0.3);
    --shadow-tint-far: oklch(0 0 0 / 0.5);
  }

  :root[data-theme='light'] {
    color-scheme: light;
    --ink-12: oklch(0.19 0.03 265);
    --ink-11: oklch(0.34 0.03 265);
    --ink-10: oklch(0.48 0.033 265);
    --ink-9: oklch(0.6 0.03 265);
    --ink-6: oklch(0.87 0.018 265);
    --ink-4: oklch(0.93 0.014 265);
    --ink-2: oklch(0.968 0.01 265);
    --ink-1: oklch(0.995 0.004 265);
    --accent: oklch(0.52 0.21 255);
    --accent-hover: oklch(0.46 0.22 255);
    --accent-contrast: oklch(0.99 0.005 255);
    --accent-quiet: oklch(0.96 0.032 255);
    --accent-line: oklch(0.86 0.07 255);
    --ours: oklch(0.5 0.13 185);
    --ours-quiet: oklch(0.96 0.035 185);
    --ours-line: oklch(0.85 0.07 185);
    --lang-he: oklch(0.48 0.17 265);
    --lang-he-bg: oklch(0.95 0.035 265);
    --lang-ar: oklch(0.46 0.13 165);
    --lang-ar-bg: oklch(0.94 0.04 165);
    --lang-en: oklch(0.5 0.15 45);
    --lang-en-bg: oklch(0.955 0.04 55);
    --positive: oklch(0.48 0.14 155);
    --warning: oklch(0.58 0.15 70);
    --danger: oklch(0.53 0.19 25);
    --scrim: oklch(0.2 0 0 / 0.28);
    --shadow-hairline: oklch(0 0 0 / 0.1);
    --shadow-lift: oklch(0 0 0 / 0.25);
    --shadow-tint: oklch(0.5 0.1 265 / 0.06);
    --shadow-tint-far: oklch(0.5 0.15 265 / 0.22);
  }

  :root:has(#theme-dark:checked) {
    color-scheme: dark;
    --ink-12: oklch(0.97 0.008 265);
    --ink-11: oklch(0.89 0.012 265);
    --ink-10: oklch(0.76 0.018 265);
    --ink-9: oklch(0.63 0.022 265);
    --ink-6: oklch(0.35 0.025 265);
    --ink-4: oklch(0.27 0.022 265);
    --ink-2: oklch(0.2 0.018 265);
    --ink-1: oklch(0.16 0.015 265);
    --accent: oklch(0.7 0.18 255);
    --accent-hover: oklch(0.77 0.17 255);
    --accent-contrast: oklch(0.15 0.02 265);
    --accent-quiet: oklch(0.24 0.05 258);
    --accent-line: oklch(0.38 0.08 258);
    --ours: oklch(0.75 0.11 185);
    --ours-quiet: oklch(0.24 0.045 190);
    --ours-line: oklch(0.38 0.07 190);
    --lang-he: oklch(0.76 0.14 265);
    --lang-he-bg: oklch(0.26 0.055 265);
    --lang-ar: oklch(0.76 0.12 165);
    --lang-ar-bg: oklch(0.25 0.05 165);
    --lang-en: oklch(0.78 0.13 55);
    --lang-en-bg: oklch(0.26 0.05 45);
    --positive: oklch(0.76 0.12 155);
    --warning: oklch(0.8 0.14 75);
    --danger: oklch(0.73 0.16 25);
    --scrim: oklch(0 0 0 / 0.6);
    --shadow-hairline: oklch(0 0 0 / 0.4);
    --shadow-lift: oklch(0 0 0 / 0.7);
    --shadow-tint: oklch(0 0 0 / 0.3);
    --shadow-tint-far: oklch(0 0 0 / 0.5);
  }

  :root:has(#theme-light:checked) {
    color-scheme: light;
    --ink-12: oklch(0.19 0.03 265);
    --ink-11: oklch(0.34 0.03 265);
    --ink-10: oklch(0.48 0.033 265);
    --ink-9: oklch(0.6 0.03 265);
    --ink-6: oklch(0.87 0.018 265);
    --ink-4: oklch(0.93 0.014 265);
    --ink-2: oklch(0.968 0.01 265);
    --ink-1: oklch(0.995 0.004 265);
    --accent: oklch(0.52 0.21 255);
    --accent-hover: oklch(0.46 0.22 255);
    --accent-contrast: oklch(0.99 0.005 255);
    --accent-quiet: oklch(0.96 0.032 255);
    --accent-line: oklch(0.86 0.07 255);
    --ours: oklch(0.5 0.13 185);
    --ours-quiet: oklch(0.96 0.035 185);
    --ours-line: oklch(0.85 0.07 185);
    --lang-he: oklch(0.48 0.17 265);
    --lang-he-bg: oklch(0.95 0.035 265);
    --lang-ar: oklch(0.46 0.13 165);
    --lang-ar-bg: oklch(0.94 0.04 165);
    --lang-en: oklch(0.5 0.15 45);
    --lang-en-bg: oklch(0.955 0.04 55);
    --positive: oklch(0.48 0.14 155);
    --warning: oklch(0.58 0.15 70);
    --danger: oklch(0.53 0.19 25);
    --scrim: oklch(0.2 0 0 / 0.28);
    --shadow-hairline: oklch(0 0 0 / 0.1);
    --shadow-lift: oklch(0 0 0 / 0.25);
    --shadow-tint: oklch(0.5 0.1 265 / 0.06);
    --shadow-tint-far: oklch(0.5 0.15 265 / 0.22);
  }
}

/* ------------------------------------------------------------------- base */

@layer base {
  body {
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-sans);
    font-size: var(--step-0);
    font-weight: 400;
    line-height: 1.65;
    font-variant-numeric: tabular-nums;
  }

  h1,
  h2,
  h3,
  h4 {
    font-weight: 700;
    line-height: 1.12;
    letter-spacing: -0.022em;
    text-wrap: balance;
  }

  h1 {
    font-size: var(--step-4);
    font-weight: 800;
    letter-spacing: -0.032em;
  }

  h2 {
    font-size: var(--step-3);
  }

  h3 {
    font-size: var(--step-1);
    letter-spacing: -0.012em;
  }

  p {
    text-wrap: pretty;
  }

  a {
    color: inherit;
    text-decoration-color: var(--accent-line);
    text-underline-offset: 0.22em;
    text-decoration-thickness: from-font;
    transition: text-decoration-color 0.15s var(--ease-out);

    &:hover {
      text-decoration-color: currentColor;
    }
  }

  code,
  kbd,
  .mono {
    font-family: var(--font-mono);
    font-size: 0.88em;
    font-variant-ligatures: none;
    direction: ltr;
    unicode-bidi: isolate;
  }

  code {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.08em 0.36em;
  }

  ::selection {
    background: var(--accent);
    color: var(--accent-contrast);
  }

  /* Cross-document transitions. The fade is short enough to read as continuity
     rather than as an effect, and it is removed entirely for reduced motion. */
  @view-transition {
    navigation: auto;
  }
}

/* ----------------------------------------------------------------- layout */

@layer layout {
  .page {
    inline-size: min(100% - var(--gutter) * 2, var(--page));
    margin-inline: auto;
  }

  .page--narrow {
    inline-size: min(100% - var(--gutter) * 2, 720px);
  }

  .section {
    padding-block: clamp(var(--space-7), 8vi, var(--space-9));
    container-type: inline-size;
  }

  .section--tight {
    padding-block: clamp(var(--space-6), 5vi, var(--space-7));
  }

  .rule {
    border-block-start: 1px solid var(--border);
  }

  /* ---- hero ---- */

  /*
   * Two columns on a wide screen, one on everything else.
   *
   * The copy column keeps its 46rem measure — that is a line length chosen for
   * reading and it does not get wider just because a monitor is. What changes
   * is what happens to the space left over: it used to be nothing, which on a
   * 1440px screen is half the page holding still.
   *
   * The art column is the last thing on the page worth loading, so on a narrow
   * screen it is not loaded at all: `display: none` rather than a scaled-down
   * version, because a phone has no space to spare for a second telling of the
   * headline.
   */
  .hero {
    display: grid;
    gap: var(--space-7);
    align-items: center;
  }

  .hero-copy {
    max-inline-size: 46rem;
  }

  .hero-art {
    display: none;
  }

  @media (width >= 66rem) {
    .hero {
      grid-template-columns: minmax(0, 46rem) minmax(0, 1fr);
    }

    .hero-art {
      display: block;
    }
  }

  /*
   * The scene.
   *
   * One SVG, drawn in a single 480×360 coordinate space, rather than a stack of
   * absolutely-positioned HTML boxes over a background. The first attempt was
   * the latter and it failed in exactly the way that arrangement fails: the boat
   * was positioned in percentages of one box while the water was drawn in
   * another, so at a width neither had been checked at, the hull ran off the
   * edge and was cut in half. Inside one viewBox there is nothing to disagree —
   * the whole picture scales as one object and cannot clip itself.
   *
   * The captions are gone too. Three floating bubbles restating the headline
   * next to the headline was the headline said twice, the second time in a
   * bubble.
   */
  .hero-scene {
    inline-size: 100%;
    block-size: auto;
    aspect-ratio: 24 / 13;
    overflow: visible;

    /*
     * No hard edges anywhere. A rectangle of water ending in a straight
     * vertical line is the giveaway that it is a graphic sitting on a page;
     * fading all four sides into the background is what lets it read as a view
     * rather than as a box. Two gradients intersected, so the corners fade in
     * both directions at once.
     */
    mask-image:
      linear-gradient(to bottom, #000 0 76%, transparent 100%),
      linear-gradient(to right, transparent 0, #000 9% 91%, transparent 100%);
    mask-composite: intersect;
    -webkit-mask-image:
      linear-gradient(to bottom, #000 0 76%, transparent 100%),
      linear-gradient(to right, transparent 0, #000 9% 91%, transparent 100%);
    -webkit-mask-composite: source-in;

    /*
     * The palette, as gradient stops.
     *
     * Every colour is mixed from `--accent` and the page surface, so the scene
     * follows the theme without a second set of values for dark mode — and it
     * inherits the brand rather than sitting next to it.
     */
    & .s-pale {
      stop-color: color-mix(in oklab, var(--accent) 22%, var(--surface));
    }

    & .s-soft {
      stop-color: color-mix(in oklab, var(--accent) 40%, var(--surface));
    }

    & .s-mid {
      stop-color: color-mix(in oklab, var(--accent) 60%, var(--surface));
    }

    & .s-deep {
      stop-color: color-mix(in oklab, var(--accent) 80%, var(--surface));
    }

    & .s-dark {
      stop-color: color-mix(in oklab, var(--accent) 96%, var(--surface));
    }

    & .s-glow {
      stop-color: var(--accent);
      stop-opacity: 0.16;
    }

    & .s-none {
      stop-color: var(--accent);
      stop-opacity: 0;
    }

    & .s-canvas-lit {
      stop-color: var(--surface-raised);
    }

    & .s-canvas-shade {
      stop-color: color-mix(in oklab, var(--accent) 14%, var(--surface));
    }
  }

  /*
   * The drift.
   *
   * One wavelength is 60 user units and every band is sixteen of them against a
   * 480-unit window, so a translate of -60 lands on a frame identical to the
   * first — the only distance that loops without a jump. Four different
   * durations, and two of them running backwards, so the bands never line up
   * into one shape sliding past. That parallax is most of what sells the scene
   * as depth rather than as four stripes.
   */
  .hero-scene .band {
    animation: hero-drift 14s linear infinite;
  }

  .hero-scene .band--4 {
    animation-duration: 26s;
    opacity: 0.85;
  }

  .hero-scene .band--3 {
    animation-duration: 19s;
    animation-direction: reverse;
  }

  .hero-scene .band--2 {
    animation-duration: 13s;
  }

  .hero-scene .band--1 {
    animation-duration: 9s;
    animation-direction: reverse;
  }

  @keyframes hero-drift {
    to {
      transform: translateX(-60px);
    }
  }

  /* The broken edge along the nearest crest. Noise, not a shape — a vector foam
     line is a row of scallops, and water does not scallop. */
  .hero-scene .crest {
    fill: var(--surface);
    opacity: 0.22;
  }

  /* ---- the boat ---- */

  .hero-scene .hull {
    fill: var(--text);
  }

  .hero-scene .sail {
    fill: url(#canvas);
    stroke: var(--text);
    stroke-width: 1.9;
    stroke-linejoin: round;
  }

  /* The jib is in the mainsail's wind shadow, so it is the darker of the two —
     the detail that stops the pair reading as one flat cut-out. */
  .hero-scene .sail--jib {
    fill: color-mix(in oklab, var(--accent) 18%, var(--surface));
  }

  .hero-scene .mast {
    stroke: var(--text);
    stroke-width: 1.9;
    stroke-linecap: round;
    fill: none;
  }

  .hero-scene .boat-reflection {
    fill: var(--text);
    opacity: 0.1;
    transform: scaleY(-0.5) translateY(-8px);
    transform-origin: 0 14px;
  }

  /*
   * The boat is placed once, in user units, and the motion goes on an inner
   * group so placement and animation never fight over the same transform.
   * `transform-box: view-box` makes the origin below read in viewBox
   * coordinates — the point where the hull meets the water, which is what a
   * boat actually pivots about.
   */
  .hero-scene .boat {
    transform: translate(240px, 236px) scale(1.5);
    transform-box: view-box;
  }

  .hero-scene .boat-sway {
    transform-box: view-box;
    transform-origin: 240px 251px;
    animation: hero-sail 7s var(--ease-in-out) infinite;
  }

  /*
   * A heel, a lift and a small drift, all on one 7s cycle but peaking at
   * different points in it. A boat that only bobs up and down looks like it is
   * on a spring; what makes it look like it is on water is that the roll leads
   * the rise, the way a hull tips into a swell before it climbs it.
   */
  @keyframes hero-sail {
    0% {
      translate: 0 3px;
      rotate: -3.5deg;
    }
    25% {
      translate: -4px -2px;
      rotate: 1.5deg;
    }
    50% {
      translate: 0 -4px;
      rotate: 3.5deg;
    }
    75% {
      translate: 4px -1px;
      rotate: -1.5deg;
    }
    100% {
      translate: 0 3px;
      rotate: -3.5deg;
    }
  }

  /*
   * Reduced motion stops the water and leaves the scene mid-frame. Hiding it
   * would be the lazier reading of the preference — someone asking for less
   * movement is not asking for less page.
   */
  @media (prefers-reduced-motion: reduce) {
    .hero-scene .band,
    .hero-scene .boat-sway {
      animation: none;
    }
  }

  .stack {
    display: grid;
    gap: var(--space-4);
    align-content: start;
  }

  .stack-lg {
    display: grid;
    gap: var(--space-6);
    align-content: start;
  }

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

  .grid-auto {
    display: grid;
    gap: var(--space-5);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  }
}

/* ------------------------------------------------------------- components */

@layer components {
  /* ---- header ---- */

  .masthead {
    position: sticky;
    inset-block-start: 0;
    z-index: 20;
    background: color-mix(in oklch, var(--surface) 82%, transparent);
    backdrop-filter: blur(12px) saturate(1.4);
    border-block-end: 1px solid var(--border);
    view-transition-name: masthead;

    & > .page {
      display: flex;
      align-items: center;
      /* Tightens as the screen narrows. A fixed 1.5rem gap between four items
         is most of a phone's spare width on its own. */
      gap: clamp(var(--space-2), 2.5vi, var(--space-5));
      min-block-size: 4rem;
    }
  }

  .wordmark {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    font-weight: 700;
    /*
     * Shrinks on a narrow screen. "NoteTheBoat" is four characters longer than
     * the name it replaced, and at a fixed size it pushed the phone masthead
     * 18px past a 390px viewport — the whole page scrolled sideways.
     */
    font-size: clamp(0.94rem, 0.86rem + 0.5vi, 1.06rem);
    letter-spacing: -0.02em;
    text-decoration: none;
    white-space: nowrap;

    & svg {
      inline-size: 1.15rem;
      block-size: 1.15rem;
      color: var(--accent);
    }
  }

  .masthead-nav {
    display: none;
    margin-inline-start: auto;
    align-items: center;
    gap: clamp(0.6rem, 2vi, 1.6rem);

    & a {
      font-size: var(--step--1);
      font-weight: 500;
      color: var(--text-muted);
      text-decoration: none;
      white-space: nowrap;

      &:hover {
        color: var(--text);
      }
    }

    @media (width >= 62rem) {
      display: flex;
    }
  }

  .masthead-actions {
    margin-inline-start: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    /* The row must be allowed to give way before the page does. Without this
       the flex items keep their natural width and push the masthead — and with
       it the whole document — wider than the viewport. */
    min-inline-size: 0;

    @media (width >= 62rem) {
      margin-inline-start: 0;
    }
  }

  /* ---- mobile nav (Popover API) ---- */

  .nav-toggle {
    display: inline-grid;
    place-items: center;
    inline-size: 2.25rem;
    block-size: 2.25rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text);

    @media (width >= 62rem) {
      display: none;
    }
  }

  [popover].nav-sheet {
    position: fixed;
    inset: auto 0 0 0;
    margin: 0;
    inline-size: 100%;
    max-inline-size: 100%;
    border: none;
    border-start-start-radius: var(--radius-lg);
    border-start-end-radius: var(--radius-lg);
    background: var(--surface);
    border-block-start: 1px solid var(--border);
    color: var(--text);
    padding: var(--space-5) var(--gutter) calc(var(--space-6) + env(safe-area-inset-bottom));
    box-shadow: 0 -24px 60px -24px var(--shadow-lift);

    translate: 0 100%;
    transition:
      translate 0.32s var(--ease-out),
      display 0.32s allow-discrete,
      overlay 0.32s allow-discrete;

    &:popover-open {
      translate: 0 0;

      @starting-style {
        translate: 0 100%;
      }
    }

    &::backdrop {
      background: var(--scrim);
      backdrop-filter: blur(2px);
      transition:
        background 0.32s var(--ease-out),
        display 0.32s allow-discrete,
        overlay 0.32s allow-discrete;

      @starting-style {
        background: transparent;
      }
    }

    & nav {
      display: grid;
      gap: 0;
    }

    & nav a {
      padding-block: var(--space-4);
      font-size: var(--step-1);
      font-weight: 600;
      text-decoration: none;
      border-block-end: 1px solid var(--border);

      &:last-of-type {
        border-block-end: none;
      }
    }
  }

  .sheet-grip {
    inline-size: 2.5rem;
    block-size: 0.25rem;
    border-radius: 999px;
    background: var(--border-strong);
    margin: 0 auto var(--space-4);
  }

  /* ---- theme switch ---- */

  .theme-switch {
    display: inline-flex;
    padding: 2px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-raised);

    & input {
      position: absolute;
      opacity: 0;
      pointer-events: none;
    }

    & label {
      display: grid;
      place-items: center;
      inline-size: 1.75rem;
      block-size: 1.75rem;
      border-radius: 999px;
      cursor: pointer;
      color: var(--text-faint);
      transition:
        background 0.18s var(--ease-out),
        color 0.18s var(--ease-out);

      & svg {
        inline-size: 0.95rem;
        block-size: 0.95rem;
      }

      &:hover {
        color: var(--text);
      }
    }

    & input:checked + label {
      background: var(--surface);
      color: var(--text);
      box-shadow: 0 1px 2px var(--shadow-hairline);
    }

    & input:focus-visible + label {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }
  }

  /* ---- buttons ---- */

  .btn {
    --btn-bg: transparent;
    --btn-fg: var(--text);
    --btn-border: var(--border-strong);

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    padding: 0.62rem 1.05rem;
    font-size: var(--step--1);
    font-weight: 600;
    letter-spacing: -0.005em;
    text-decoration: none;
    white-space: nowrap;
    border: 1px solid var(--btn-border);
    border-radius: var(--radius-sm);
    background: var(--btn-bg);
    color: var(--btn-fg);
    transition:
      background 0.16s var(--ease-out),
      border-color 0.16s var(--ease-out),
      color 0.16s var(--ease-out);

    & svg {
      inline-size: 1rem;
      block-size: 1rem;
      flex: none;
    }

    &:hover {
      --btn-border: var(--text);
    }

    &:disabled,
    &[aria-disabled='true'] {
      opacity: 0.5;
      cursor: not-allowed;
      --btn-border: var(--border);
    }
  }

  /* The primary action is the accent, not black. A black button on a white page
     is the safest possible choice and reads as an absence of one. */
  .btn--primary {
    --btn-bg: var(--accent);
    --btn-fg: var(--accent-contrast);
    --btn-border: var(--accent);

    &:hover {
      --btn-bg: var(--accent-hover);
      --btn-border: var(--accent-hover);
    }
  }

  .btn--ink {
    --btn-bg: var(--text);
    --btn-fg: var(--surface);
    --btn-border: var(--text);
  }

  .btn:not(.btn--primary, .btn--ink, .btn--quiet):hover {
    --btn-border: var(--accent);
    color: var(--accent);
  }

  .btn--quiet {
    --btn-border: transparent;
    color: var(--text-muted);

    &:hover {
      --btn-border: var(--border);
      color: var(--text);
    }
  }

  .btn--lg {
    padding: 0.82rem 1.4rem;
    font-size: var(--step-0);
  }

  .btn--block {
    inline-size: 100%;
  }

  /* ---- eyebrow / meta ---- */

  .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--accent);

    &::before {
      content: '';
      inline-size: 1.4rem;
      block-size: 2px;
      border-radius: 2px;
      background: var(--accent);
    }
  }

  /* A tinted band so the page has rhythm instead of one uninterrupted sheet. */
  .band {
    background: var(--surface-raised);
    border-block: 1px solid var(--border);
  }

  .band--accent {
    background: var(--accent-quiet);
    border-block: 1px solid var(--accent-line);
  }

  .lede {
    font-size: var(--step-1);
    line-height: 1.55;
    color: var(--text-muted);
    max-inline-size: var(--measure);
  }

  /* ---- transcript demo ----
     The product's real differentiator, shown rather than claimed. */

  .transcript {
    container-type: inline-size;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius-lg);
    background: var(--surface-raised);
    overflow: clip;
    box-shadow: 0 1px 2px var(--shadow-tint),
      0 12px 32px -16px var(--shadow-tint-far);
  }

  .transcript-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0.6rem 0.9rem;
    border-block-end: 1px solid var(--border);
    background: var(--surface);
    font-family: var(--font-mono);
    font-size: 0.72rem;
    color: var(--text-faint);
  }

  .rec-dot {
    inline-size: 0.45rem;
    block-size: 0.45rem;
    border-radius: 999px;
    background: var(--danger);
    flex: none;

    @media (prefers-reduced-motion: no-preference) {
      animation: pulse 2.4s var(--ease-in-out) infinite;
    }
  }

  .transcript-body {
    display: grid;
    gap: 0.15rem;
    padding: var(--space-3);
    font-size: var(--step--1);
  }

  .line {
    /*
     * The row keeps the document's direction no matter what language the line
     * is in. Setting `dir` on the row itself would flip the grid too, so the
     * timestamp column would jump from side to side down the list and the
     * whole thing would read as broken. Only the sentence flips — which is
     * exactly what bidirectional text calls for.
     */
    direction: rtl;
    display: grid;
    /* The areas must be named here too. The children are placed with
       `grid-area`, so without a template to place them into they land in
       implicit tracks and the timestamp column silently disappears. */
    grid-template-columns: auto auto 1fr;
    grid-template-areas: 'time tag text';
    gap: 0.7rem;
    align-items: baseline;
    padding: 0.5rem 0.7rem;
    border-radius: var(--radius-sm);
    transition: background 0.2s var(--ease-out);

    &:hover {
      background: color-mix(in oklch, var(--text) 4%, transparent);
    }

    /* Under 34rem the metadata stacks above the sentence instead of squeezing
       it into a column two words wide. */
    @container (width < 34rem) {
      grid-template-columns: auto auto 1fr;
      grid-template-areas:
        'time tag .'
        'text text text';
      gap: 0.35rem 0.6rem;
    }
  }

  .line-time {
    grid-area: time;
    font-family: var(--font-mono);
    font-size: 0.7rem;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
  }

  .line-tag {
    grid-area: tag;
    font-family: var(--font-mono);
    font-size: 0.62rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.12rem 0.4rem;
    border-radius: 4px;
    justify-self: start;
    white-space: nowrap;
    /* A filled chip rather than an outline: this is the one element on the page
       that has to be legible at a glance, because it is the whole argument. */
    background: var(--tag-bg, transparent);
    color: var(--tag-fg, currentColor);
  }

  .line-text {
    grid-area: text;
    color: var(--text);
    line-height: 1.55;
    unicode-bidi: isolate;
    text-align: start;
  }

  .line-text[dir='ltr'] {
    direction: ltr;
  }

  .line[data-lang='he'] {
    --tag-fg: var(--lang-he);
    --tag-bg: var(--lang-he-bg);
  }
  .line[data-lang='ar'] {
    --tag-fg: var(--lang-ar);
    --tag-bg: var(--lang-ar-bg);
  }
  .line[data-lang='en'] {
    --tag-fg: var(--lang-en);
    --tag-bg: var(--lang-en-bg);
  }

  /* A hairline in the line's own language colour, so the three languages are
     scannable down the left edge without reading a single tag. */
  .line {
    border-inline-start: 2px solid transparent;
  }

  .line[data-lang] {
    border-inline-start-color: var(--tag-fg);
  }

  /* ---- upload dropzone ---- */

  .dropzone {
    display: grid;
    justify-items: center;
    gap: var(--space-3);
    padding: clamp(var(--space-6), 7vi, var(--space-8)) var(--space-5);
    border: 2px dashed var(--accent-line);
    border-radius: var(--radius-lg);
    background: var(--accent-quiet);
    text-align: center;
    transition:
      border-color 0.18s var(--ease-out),
      background 0.18s var(--ease-out);

    &.is-over {
      border-color: var(--accent);
      border-style: solid;
      background: color-mix(in oklch, var(--accent) 14%, transparent);
    }

    & p {
      margin: 0;
    }
  }

  .dropzone-icon {
    inline-size: 2.4rem;
    block-size: 2.4rem;
    color: var(--accent);
  }

  .dropzone-title {
    font-size: var(--step-1);
    font-weight: 700;
    letter-spacing: -0.012em;
  }

  /* ---- feature cards ---- */

  .feature {
    container-type: inline-size;
    display: grid;
    gap: var(--space-3);
    padding-block: var(--space-5);
    border-block-start: 1px solid var(--border);
    align-content: start;

    & h3 {
      display: flex;
      align-items: center;
      gap: 0.6rem;
    }

    & svg {
      inline-size: 1.9rem;
      block-size: 1.9rem;
      padding: 0.38rem;
      border-radius: 7px;
      background: var(--accent-quiet);
      color: var(--accent);
      flex: none;
    }

    & p {
      color: var(--text-muted);
      font-size: var(--step--1);
      line-height: 1.65;
      margin: 0;
    }
  }

  /* ---- comparison strip ---- */

  .versus {
    display: grid;
    gap: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: clip;
    container-type: inline-size;
  }

  .versus-row {
    display: grid;
    grid-template-columns: 1fr;
    border-block-end: 1px solid var(--border);

    &:last-child {
      border-block-end: none;
    }

    @container (width >= 44rem) {
      grid-template-columns: 14rem 1fr 1fr;
    }
  }

  .versus-head {
    padding: var(--space-4);
    font-weight: 600;
    font-size: var(--step--1);
    background: var(--surface-raised);

    @container (width >= 44rem) {
      background: transparent;
      border-inline-end: 1px solid var(--border);
    }
  }

  .versus-cell {
    padding: var(--space-4);
    font-size: var(--step--1);
    color: var(--text-muted);
    display: grid;
    gap: 0.3rem;
    align-content: start;

    & strong {
      color: var(--text);
      font-weight: 600;
      font-size: 0.78rem;
      font-family: var(--font-mono);
      letter-spacing: 0.05em;
      text-transform: uppercase;
    }

    @container (width >= 44rem) {
      border-inline-end: 1px solid var(--border);

      &:last-child {
        border-inline-end: none;
      }
    }
  }

  .versus-cell--ours {
    background: var(--ours-quiet);
    color: var(--text);
    box-shadow: inset 0 2px 0 var(--ours);

    & strong {
      color: var(--ours);
    }
  }

  /* ---- pricing ---- */

  .plans {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15.5rem), 1fr));
    align-items: stretch;
  }

  .plan {
    container-type: inline-size;
    display: grid;
    gap: var(--space-4);
    align-content: start;
    padding: var(--space-5);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    position: relative;

    /* The recommended plan is marked by colour and a tinted surface, not by
       being merely a slightly darker outline nobody notices. */
    &:has(.plan-flag) {
      border-color: var(--accent);
      background: var(--accent-quiet);
      box-shadow: 0 0 0 1px var(--accent);
    }
  }

  .plan-flag {
    position: absolute;
    inset-block-start: 0;
    inset-inline-end: var(--space-5);
    translate: 0 -50%;
    background: var(--accent);
    color: var(--accent-contrast);
    font-family: var(--font-mono);
    font-size: 0.64rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 0.22rem 0.55rem;
    border-radius: 3px;
  }

  .plan-name {
    font-size: var(--step-1);
    font-weight: 700;
  }

  .plan-tagline {
    font-size: var(--step--1);
    color: var(--text-faint);
    margin: 0;
    min-block-size: 2.8em;
  }

  .plan-price {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    flex-wrap: wrap;

    & .amount {
      font-size: var(--step-3);
      font-weight: 800;
      letter-spacing: -0.035em;
      font-variant-numeric: tabular-nums;
      /* A currency symbol is bidi-neutral, so "$9" inside Hebrew prose reorders
         to "9$" and "₪39" to "39₪". Isolating the amount pins it to the order
         it was written in — which for a price is the only acceptable one. */
      direction: ltr;
      unicode-bidi: isolate;
    }

    & .period {
      font-size: var(--step--1);
      color: var(--text-faint);
    }
  }

  .plan-note {
    font-size: 0.8rem;
    color: var(--text-faint);
    margin: 0;
    min-block-size: 2.4em;
  }

  /* Same reasoning as .amount — any bare price in prose. */
  .money {
    direction: ltr;
    unicode-bidi: isolate;
    display: inline-block;
  }

  .plan-features {
    display: grid;
    gap: 0.55rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--step--1);
    color: var(--text-muted);

    & li {
      display: grid;
      grid-template-columns: 1rem 1fr;
      gap: 0.55rem;
      align-items: start;
    }

    & li svg {
      inline-size: 0.85rem;
      block-size: 0.85rem;
      margin-block-start: 0.38em;
      color: var(--accent);
    }

    & li.is-lead {
      grid-template-columns: 1fr;
      color: var(--text);
      font-weight: 600;
      margin-block-start: 0.2rem;
    }
  }

  .seats {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: var(--step--1);
    color: var(--text-muted);

    & input {
      inline-size: 4.5rem;
      field-sizing: content;
      min-inline-size: 3.5rem;
      padding: 0.35rem 0.5rem;
      text-align: center;
      border: 1px solid var(--border);
      border-radius: var(--radius-sm);
      background: var(--surface-raised);
      font-variant-numeric: tabular-nums;
    }
  }

  /* ---- billing toggle ---- */

  .segmented {
    display: inline-flex;
    padding: 3px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-raised);

    & button {
      padding: 0.42rem 1rem;
      font-size: var(--step--1);
      font-weight: 600;
      border-radius: 999px;
      color: var(--text-muted);
      transition:
        background 0.18s var(--ease-out),
        color 0.18s var(--ease-out);

      &[aria-pressed='true'] {
        background: var(--accent);
        color: var(--accent-contrast);
      }
    }
  }

  /* ---- comparison table ----
     Below 52rem each row becomes a labelled card. A horizontally scrolling
     table on a phone is a table nobody reads. */

  .matrix {
    container-type: inline-size;
  }

  .matrix table {
    inline-size: 100%;
    border-collapse: collapse;
    font-size: var(--step--1);
  }

  .matrix th,
  .matrix td {
    padding: 0.7rem 0.9rem;
    text-align: start;
    border-block-end: 1px solid var(--border);
    vertical-align: baseline;
  }

  .matrix thead th {
    font-size: 0.72rem;
    font-family: var(--font-mono);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-faint);
    font-weight: 500;
    position: sticky;
    inset-block-start: 4rem;
    background: var(--surface);
    z-index: 1;
  }

  .matrix .group th {
    font-weight: 700;
    font-size: var(--step--1);
    padding-block-start: var(--space-5);
    color: var(--text);
    border-block-end-color: var(--border-strong);
  }

  .matrix td:not(:first-child) {
    color: var(--text-muted);
  }

  .matrix .yes {
    color: var(--ours);
  }

  .matrix .no {
    color: var(--text-faint);
  }

  .matrix svg {
    inline-size: 0.9rem;
    block-size: 0.9rem;
  }

  @container (width < 52rem) {
    .matrix thead {
      display: none;
    }

    .matrix,
    .matrix table,
    .matrix tbody,
    .matrix tr,
    .matrix td,
    .matrix th {
      display: block;
    }

    .matrix .group th {
      padding-inline: 0;
      border-block-end: none;
    }

    .matrix tbody tr:not(.group) {
      border: 1px solid var(--border);
      border-radius: var(--radius);
      padding: var(--space-3);
      margin-block-end: var(--space-3);
    }

    .matrix tbody tr:not(.group) th {
      padding: 0 0 0.5rem;
      border-block-end: 1px solid var(--border);
      font-weight: 600;
      margin-block-end: 0.5rem;
    }

    .matrix tbody tr:not(.group) td {
      display: grid;
      grid-template-columns: 5.5rem 1fr;
      gap: 0.75rem;
      padding: 0.25rem 0;
      border: none;

      &::before {
        content: attr(data-plan);
        font-family: var(--font-mono);
        font-size: 0.68rem;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        color: var(--text-faint);
        padding-block-start: 0.2em;
      }
    }
  }

  /* ---- disclosure ---- */

  .qa {
    border-block-end: 1px solid var(--border);

    & summary {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: var(--space-4);
      padding-block: var(--space-4);
      font-weight: 600;
      cursor: pointer;
      list-style: none;

      &::-webkit-details-marker {
        display: none;
      }

      &::after {
        content: '';
        inline-size: 0.7rem;
        block-size: 0.7rem;
        flex: none;
        border-inline-end: 1.5px solid var(--text-faint);
        border-block-end: 1.5px solid var(--text-faint);
        rotate: 45deg;
        transition: rotate 0.2s var(--ease-out);
      }
    }

    &[open] summary::after {
      rotate: -135deg;
    }

    & > div {
      padding-block-end: var(--space-5);
      color: var(--text-muted);
      font-size: var(--step--1);
      max-inline-size: var(--measure);
    }
  }

  /* ---- notice ---- */

  .notice {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.7rem;
    padding: 0.85rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: var(--step--1);
    background: var(--surface-raised);

    & svg {
      inline-size: 1rem;
      block-size: 1rem;
      margin-block-start: 0.2em;
      color: var(--text-faint);
    }
  }

  .notice--error {
    border-color: color-mix(in oklch, var(--danger) 45%, transparent);
    background: color-mix(in oklch, var(--danger) 8%, transparent);

    & svg {
      color: var(--danger);
    }
  }

  .notice--ok {
    border-color: color-mix(in oklch, var(--positive) 45%, transparent);
    background: color-mix(in oklch, var(--positive) 8%, transparent);

    & svg {
      color: var(--positive);
    }
  }

  .notice--warn {
    border-color: color-mix(in oklch, var(--warning) 45%, transparent);
    background: color-mix(in oklch, var(--warning) 8%, transparent);

    & svg {
      color: var(--warning);
    }
  }

  /* ---- account ---- */

  .panel {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    display: grid;
    gap: var(--space-4);
    align-content: start;
    container-type: inline-size;
  }

  .stat-row {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  }

  .stat {
    display: grid;
    gap: 0.15rem;

    & dt {
      font-family: var(--font-mono);
      font-size: 0.68rem;
      letter-spacing: 0.07em;
      text-transform: uppercase;
      color: var(--text-faint);
    }

    & dd {
      margin: 0;
      font-size: var(--step-1);
      font-weight: 700;
      letter-spacing: -0.015em;
    }
  }

  .meter {
    display: grid;
    gap: 0.4rem;

    & .meter-label {
      display: flex;
      justify-content: space-between;
      gap: var(--space-3);
      font-size: var(--step--1);
    }

    & .meter-value {
      font-family: var(--font-mono);
      font-size: 0.78rem;
      color: var(--text-faint);
    }

    & .meter-track {
      block-size: 3px;
      border-radius: 999px;
      background: var(--ink-4);
      overflow: clip;
    }

    & .meter-fill {
      block-size: 100%;
      background: var(--accent);
      border-radius: 999px;
      transition: inline-size 0.5s var(--ease-out);
    }

    &[data-state='high'] .meter-fill {
      background: var(--warning);
    }

    &[data-state='full'] .meter-fill {
      background: var(--danger);
    }
  }

  /* ---- footer ---- */

  .colophon {
    border-block-start: 1px solid var(--border);
    padding-block: var(--space-6) var(--space-7);
    margin-block-start: var(--space-7);
    font-size: var(--step--1);
    color: var(--text-faint);

    & .page {
      display: grid;
      gap: var(--space-5);
      grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    }

    & nav {
      display: grid;
      gap: 0.5rem;
      align-content: start;
    }

    & nav a {
      color: var(--text-muted);
      text-decoration: none;
      inline-size: fit-content;
      /* A 0.9rem link at this line-height is a ~23px tap target. On a phone
         that is under the comfortable minimum, so give it real vertical room. */
      min-block-size: 2.75rem;
      display: flex;
      align-items: center;

      &:hover {
        color: var(--text);
      }

      @media (width >= 48rem) {
        min-block-size: 1.75rem;
      }
    }

    & h4 {
      font-family: var(--font-mono);
      font-size: 0.68rem;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--text-faint);
      font-weight: 500;
      margin-block-end: 0.3rem;
    }
  }

  /* ---- legal prose ---- */

  .prose {
    max-inline-size: var(--measure);

    & h2 {
      font-size: var(--step-1);
      margin-block: var(--space-6) var(--space-3);
    }

    & p {
      margin-block-end: var(--space-3);
      color: var(--text-muted);
    }

    & ul {
      margin-block-end: var(--space-4);
      padding-inline-start: 1.2rem;
      color: var(--text-muted);
      display: grid;
      gap: 0.4rem;
    }

    & strong {
      color: var(--text);
    }
  }

  /* ---- language switch ---- */

  .lang-switch {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 999px;
    overflow: hidden;
    background: var(--surface-raised);

    & button {
      font-size: 0.72rem;
      font-weight: 700;
      letter-spacing: 0.03em;
      padding: 0.35rem 0.6rem;
      color: var(--text-faint);
      /* 28px tall including padding, which keeps it a real tap target next to
         the theme switch rather than a pair of hard-to-hit words. */
      min-block-size: 28px;
      transition: color 0.15s var(--ease-out), background 0.15s var(--ease-out);
    }

    & button[aria-pressed='true'] {
      background: var(--accent);
      color: var(--accent-contrast);
    }

    & button:hover:not([aria-pressed='true']) {
      color: var(--text);
    }
  }

  /* The header runs out of room before this does; the sheet copy takes over. */
  @media (width < 46rem) {
    .masthead-actions .lang-switch {
      display: none;
    }
  }

  .lang-switch--sheet {
    align-self: start;
    margin-block-start: var(--space-3);

    & button {
      padding: 0.5rem 0.9rem;
      min-block-size: 40px;
    }
  }

  /* ---- signed-in navigation ---- */

  /* The plan badge. Quiet by default; the paid tiers get the accent, because
     the point of the badge for a paying customer is that they can see it. */
  .nav-plan {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    padding: 0.2rem 0.5rem;
    border-radius: 999px;
    background: var(--ink-4);
    color: var(--text-muted);
    border: 1px solid var(--border);
    white-space: nowrap;

    &[data-plan='pro'],
    &[data-plan='team'],
    &[data-plan='enterprise'] {
      background: var(--accent-quiet);
      color: var(--accent);
      border-color: var(--accent-line);
    }
  }

  .nav-upgrade {
    color: var(--accent);
    font-weight: 600;
  }

  /* Sign in and register are both in the header, side by side, and register is
     the one carrying weight — a visitor who has no account is the visitor this
     link exists for. It stays a link rather than becoming a third button, so
     the row keeps one primary action. */
  .nav-register {
    color: var(--text);
    font-weight: 600;
  }

  [data-auth-register][hidden],
  [data-auth-account][hidden] {
    display: none;
  }

  /* ---- recordings ---- */

  .recording {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding-block: var(--space-3);
    border-block-start: 1px solid var(--border);

    &:first-child {
      border-block-start: none;
      padding-block-start: 0;
    }

    /* The title column absorbs the slack and is allowed to shrink; without
       `min-inline-size: 0` a long filename pushes the buttons off the row. */
    & > :first-child {
      flex: 1;
      min-inline-size: 0;
    }

    @container (width < 30rem) {
      flex-wrap: wrap;
      gap: var(--space-2);
    }
  }

  /* ---- receipts ---- */

  .receipt {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding-block: var(--space-3);
    border-block-start: 1px solid var(--border);

    &:first-child {
      border-block-start: none;
      padding-block-start: 0;
    }

    /* The description takes the slack; the amount and the link keep their size. */
    & > :first-child {
      flex: 1;
      min-inline-size: 0;
    }

    /* Stacks on a phone, where three columns would crush the amount into two
       lines and make it harder to read than the label next to it. */
    @container (width < 26rem) {
      flex-wrap: wrap;
      gap: var(--space-2);
    }
  }

  .positive {
    color: var(--positive);
  }

  /* ---- forms ---- */

  .field {
    display: grid;
    gap: 0.35rem;

    & > span {
      font-size: var(--step--1);
      font-weight: 600;
      color: var(--text);

      & em {
        font-style: normal;
        font-weight: 400;
        color: var(--text-faint);
      }
    }

    & > em {
      font-style: normal;
      font-size: 0.78rem;
      color: var(--text-faint);
    }
  }

  .field input {
    font: inherit;
    font-size: var(--step-0);
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    /* 0.7rem block padding lands the control at ~44px — a comfortable target on
       a phone, which is where most people will type these. */
    padding: 0.7rem 0.85rem;
    inline-size: 100%;
    transition:
      border-color 0.15s var(--ease-out),
      box-shadow 0.15s var(--ease-out);

    &::placeholder {
      color: var(--text-faint);
    }

    &:focus-visible {
      outline: none;
      border-color: var(--accent);
      box-shadow: 0 0 0 3px var(--accent-quiet);
    }

    /*
     * Invalid styling only after the field has been left alone. `:invalid`
     * alone paints an empty required field red the moment the page loads,
     * which scolds someone for not having typed yet.
     */
    &:user-invalid {
      border-color: var(--danger);
    }
  }

  /* A rule with a label in the middle, for "or". */
  .rule-text {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--text-faint);
    font-size: var(--step--1);

    &::before,
    &::after {
      content: '';
      flex: 1;
      block-size: 1px;
      background: var(--border);
    }
  }

  /* ---- loading curtain ---- */

  /*
   * Every rule here describes an element that only exists while
   * `assets/motion.js` is running. Nothing on the page is hidden waiting for
   * it — if the script never runs, none of this matches anything, and the site
   * is just the site.
   */
  .curtain {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: var(--surface);
    display: grid;
    align-content: center;
    justify-items: center;
    gap: var(--space-5);
    padding: var(--gutter);
  }

  /* Only while the curtain is up, and removed by script the moment it lifts. */
  .is-loading body {
    overflow: hidden;
  }

  .curtain-inner {
    display: grid;
    justify-items: center;
    gap: var(--space-4);
    animation: curtain-mark-in 0.7s var(--ease-out) both;
  }

  .curtain-mark {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    font-size: var(--step-2);
    font-weight: 800;
    letter-spacing: -0.03em;
    color: var(--text);
  }

  /* Tabular figures so the counter does not jitter as digits change width. */
  .curtain-count {
    font-family: var(--font-mono);
    font-size: var(--step--1);
    font-variant-numeric: tabular-nums;
    color: var(--text-faint);
    direction: ltr;

    &::after {
      content: '%';
      margin-inline-start: 0.15em;
    }
  }

  /* A rule that fills as the count climbs — the only honest progress here is
     "the page is loading", and a line is a quieter way to say it than a bar. */
  .curtain-rule {
    inline-size: min(18rem, 60vw);
    block-size: 1px;
    background: var(--border);
    overflow: hidden;

    & i {
      display: block;
      block-size: 100%;
      background: var(--accent);
      /* The site is RTL, so the line fills from the right — the direction the
         reader's eye is already travelling. */
      transform-origin: right;
      animation: curtain-rule 1.1s var(--ease-out) both;
    }
  }

  @keyframes curtain-mark-in {
    from {
      opacity: 0;
      transform: translateY(0.8rem);
      filter: blur(6px);
    }
  }

  @keyframes curtain-rule {
    from {
      scale: 0 1;
    }
    to {
      scale: 1 1;
    }
  }

  /*
   * The lift. A clip-path wipe rather than a fade, so the page underneath is
   * uncovered instead of cross-dissolved into — which is what makes it read as
   * a curtain and not as a loading screen giving up.
   */
  .curtain--out {
    animation: curtain-out 0.66s var(--ease-in-out) both;
  }

  @keyframes curtain-out {
    to {
      clip-path: inset(0 0 100% 0);
      opacity: 0.9;
    }
  }

  /* ---- headline reveal ---- */

  .word {
    display: inline-block;
    white-space: nowrap;
  }

  .char {
    display: inline-block;
    overflow: hidden;
    /* Room for descenders and Hebrew niqqud, which a tight mask would clip. */
    padding-block-end: 0.12em;
    margin-block-end: -0.12em;
    vertical-align: bottom;

    & > span {
      display: inline-block;
      translate: 0 105%;
      opacity: 0;
    }
  }

  [data-reveal].is-revealed .char > span {
    translate: 0 0;
    opacity: 1;
    transition:
      translate 0.62s var(--ease-out),
      opacity 0.42s linear;
    /* Staggered off the character index, capped so a long Hebrew headline does
       not take three seconds to finish arriving. */
    transition-delay: calc(min(var(--i) * 22ms, 620ms));
  }

  @media (prefers-reduced-motion: reduce) {
    .curtain,
    .curtain-inner,
    .curtain-rule i {
      animation: none;
    }

    .char > span {
      translate: none;
      opacity: 1;
    }
  }

  /* ---- cookie consent ---- */

  /*
   * A slim bar, not a card.
   *
   * The version this replaces was a 30rem panel with a headline, a paragraph
   * and three full-width buttons. On a phone it covered a third of the screen
   * before anyone had read a word, which is the thing every visitor has learned
   * to resent — and a banner people resent is a banner they dismiss without
   * reading, which is worth nothing to them or to us.
   *
   * So: one line of text, two small buttons, one quiet link. It states what is
   * true in nine words and gets out of the way. The detail panel is still there
   * for anyone who wants it, one press away and equally reachable — "reject" is
   * still a first-class button and not hidden behind "manage", which is both
   * the standard dark pattern and, in the EU, not consent at all.
   */
  .consent {
    position: fixed;
    z-index: 60;
    inset-block-end: 0;
    inset-inline: 0;
    padding: var(--space-3);
    padding-block-end: max(var(--space-3), env(safe-area-inset-bottom));
    display: flex;
    justify-content: center;
    pointer-events: none;
  }

  .consent[hidden] {
    display: none;
  }

  .consent-card {
    pointer-events: auto;
    inline-size: min(100%, 44rem);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding-inline: var(--space-4);
    padding-block: var(--space-3);
    box-shadow:
      0 1px 2px var(--shadow-hairline),
      0 18px 44px -22px var(--shadow-lift);

    /*
     * The entrance borrows the curve rather than the choreography: a short rise
     * with a slight overshoot reads as a physical object arriving, where a plain
     * fade reads as a layer being switched on. It is short because anything
     * longer makes the visitor wait to answer a question they did not ask.
     */
    animation: consent-in 0.42s var(--ease-out) both;
  }

  /*
   * The one row. Text takes the space it needs and no more; the buttons keep
   * their size and sit at the end. `flex-wrap` is what makes the narrow case
   * work without a second set of rules — the actions drop to their own line
   * only when the sentence genuinely cannot share one with them.
   */
  .consent-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  @keyframes consent-in {
    from {
      opacity: 0;
      transform: translateY(1.5rem) scale(0.97);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  /* Leaving is faster than arriving — the answer is already given. */
  .consent--closing .consent-card {
    animation: consent-out 0.22s var(--ease-in-out) both;
  }

  @keyframes consent-out {
    to {
      opacity: 0;
      transform: translateY(0.75rem) scale(0.98);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .consent-card,
    .consent--closing .consent-card {
      animation-duration: 0.01ms;
    }
  }

  /* The accessible name for the dialog, carried by a word rather than by a
     headline — the sentence next to it already says everything a headline
     would have. */
  .consent-title {
    color: var(--text);
    font-weight: 700;

    &::after {
      content: ' · ';
      color: var(--text-faint);
      font-weight: 400;
    }
  }

  .consent-body {
    margin: 0;
    flex: 1 1 18rem;
    font-size: var(--step--1);
    line-height: 1.6;
    color: var(--text-muted);
    text-wrap: pretty;

    & a {
      color: inherit;
      text-underline-offset: 0.2em;
    }
  }

  .consent-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
  }

  /* Both answers are the same size, so neither is the easy one. Smaller than a
     page button because this is not a page action — it is a formality. */
  .consent-btn {
    padding: 0.42rem 0.9rem;
    font-size: 0.8rem;
  }

  /* Quiet, but a real button: focusable, keyboard-operable, and legible. It is
     text rather than a bordered control because a third box of equal weight is
     what made the old banner look like a decision instead of a note. */
  .consent-manage {
    padding: 0.42rem 0.4rem;
    font: inherit;
    font-size: 0.8rem;
    font-weight: 600;
    background: none;
    border: none;
    color: var(--text-faint);
    cursor: pointer;
    border-radius: var(--radius-sm);
    text-decoration: underline;
    text-underline-offset: 0.25em;
    text-decoration-color: var(--border-strong);
    transition: color 0.16s var(--ease-out);

    &:hover {
      color: var(--text);
    }

    &:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }
  }

  /*
   * The detail panel opens by animating a grid track from 0fr to 1fr, which is
   * the only way to transition to a content-determined height without measuring
   * it in JavaScript and hard-coding a pixel value that goes stale on reflow.
   */
  .consent-details {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.35s var(--ease-out);

    & > div {
      overflow: hidden;
    }
  }

  .consent-details[data-open='true'] {
    grid-template-rows: 1fr;
  }

  /*
   * Capped and scrollable. Three categories with honest descriptions is more
   * text than fits above a phone's keyboard-less fold, and a panel that grows
   * to whatever its content needs is how a banner that was small becomes a
   * banner that covers the page the moment someone takes it seriously.
   */
  .consent-groups {
    max-block-size: min(46svh, 22rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    margin-block-start: var(--space-3);
  }

  .consent-group {
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: var(--space-3);
    padding-block: var(--space-3);
    border-block-start: 1px solid var(--border);

    & p {
      margin: 0.15rem 0 0;
      font-size: var(--step--1);
      color: var(--text-faint);
      line-height: 1.55;
    }

    & strong {
      font-size: var(--step-0);
    }
  }

  /* A real checkbox, restyled — so it is focusable, labelled and works without
     a single line of JavaScript behind it. */
  .consent-toggle {
    flex: none;
    inline-size: 2.75rem;
    block-size: 1.6rem;
    margin: 0;
    appearance: none;
    border-radius: 999px;
    background: var(--ink-6);
    border: none;
    position: relative;
    cursor: pointer;
    transition: background 0.2s var(--ease-out);

    /*
     * Physical, not logical, and deliberately so.
     *
     * The knob is placed with `left` and moved with `translate`, which is not
     * direction-aware. Pairing a logical start edge with a physical translate
     * means the two agree only while the page resolves start as left — flip
     * that and the knob slides out of its own track. Off-left/on-right is also
     * what a toggle means to everyone regardless of the script they read.
     */
    direction: ltr;

    &::after {
      content: '';
      position: absolute;
      top: 0.2rem;
      left: 0.2rem;
      inline-size: 1.2rem;
      block-size: 1.2rem;
      border-radius: 50%;
      background: var(--ink-1);
      box-shadow: 0 1px 2px var(--shadow-hairline);
      transition: translate 0.22s var(--ease-out);
    }

    &:checked {
      background: var(--accent);
    }

    &:checked::after {
      translate: 1.15rem 0;
    }

    &:disabled {
      cursor: not-allowed;
      opacity: 0.75;
    }

    &:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: 2px;
    }
  }

  /*
   * The phone case, which is the one the old banner got wrong.
   *
   * The sentence takes the first row and the buttons the second, and the two
   * of them together come to about 90px — a strip along the bottom edge rather
   * than a third of the screen. The buttons stretch to fill the row they now
   * have to themselves, because a narrow button at the edge of a phone is a
   * target people miss.
   */
  @media (width < 34rem) {
    .consent {
      padding: var(--space-2);
      padding-block-end: max(var(--space-2), env(safe-area-inset-bottom));
    }

    .consent-card {
      padding-inline: var(--space-3);
      padding-block: var(--space-3);
      border-radius: var(--radius-sm);
    }

    .consent-bar {
      gap: var(--space-2);
    }

    .consent-body {
      flex-basis: 100%;
      font-size: 0.8rem;
      line-height: 1.5;
    }

    .consent-actions {
      flex: 1 1 100%;
    }

    .consent-btn {
      flex: 1 1 auto;
    }
  }
}

/* -------------------------------------------------------------- utilities */

@layer utilities {
  .ltr {
    direction: ltr;
    unicode-bidi: isolate;
  }

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

  .faint {
    color: var(--text-faint);
  }

  .small {
    font-size: var(--step--1);
  }

  .center {
    text-align: center;
  }

  .hidden {
    display: none !important;
  }

  .visually-hidden {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .defer {
    content-visibility: auto;
    contain-intrinsic-size: auto 40rem;
  }

  /*
   * Scroll-driven reveal — motion only, never opacity.
   *
   * Fading content in from zero means any state where the timeline does not
   * advance leaves it invisible: printing, a full-page capture, a crawler that
   * does not scroll, or a deep link that lands past the element's entry range.
   * Content must not depend on an animation having run, so this moves the
   * element and nothing else. Without support it simply sits where it belongs.
   */
  @media (prefers-reduced-motion: no-preference) {
    @supports (animation-timeline: view()) {
      .reveal {
        animation: reveal-in linear both;
        animation-timeline: view();
        animation-range: entry 2% cover 18%;
      }
    }
  }
}

@keyframes reveal-in {
  from {
    translate: 0 1rem;
  }
  to {
    translate: 0 0;
  }
}

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

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
