/* scribe.dehaze.de marketing page stylesheet. GENERATED by web/marketing-src/scribe/generate.py -
   tokens from tokens/tokens.json, the kit layout from STATIC_CSS, the grid maps
   from the site file's layout data, the waveform band's bar levels from
   demo-levels.json. Do not edit. */

/* Generated from tokens/tokens.json (Warm Editorial v3) - do not edit;
   edit the tokens and re-run make marketing-build. Light values on :root,
   dark values under prefers-color-scheme, per the token contract. */
:root {
  --background: #FAF7F1;
  --surface: #FFFFFF;
  --content-primary: #24272B;
  --content-secondary: #6D736F;
  --content-recessive: #4C5250;
  --accent: #27735F;
  --on-accent: #FFFFFF;
  --accent-tint: #E7F0EB;
  --accent-deep: #1E5648;
  --chapter-tint2: #7BA697;
  --chapter-tint3: #9DBFB6;
  --sand: #F0E9DD;
  --sand-content: #826438;
  --neutral-tint: #EDECE8;
  --success: #2D794D;
  --success-tint: #E4EFE7;
  --warning: #8E6310;
  --warning-tint: #F5EBD7;
  --warning-deep: #6B4E10;
  --danger: #B3423F;
  --danger-tint: #F6E4E2;
  --switch-track-off: #DEDAD2;
  --switch-knob-off: #FFFFFF;
  --disabled-fill: #E9E5DC;
  --disabled-content: #A8A49B;
  --radius-sm: 13px;
  --radius-md: 18px;
  --radius-md-lg: 20px;
  --radius-lg: 22px;
  --radius-pill: 999px;
  --space-xs: 4px;
  --space-sm: 8px;
  --space-sm-md: 10px;
  --space-md: 12px;
  --space-lg: 16px;
  --space-xl: 24px;
  --space-xxl: 32px;
  --shadow-raised: 0px 3px 12px rgba(36, 39, 43, 0.05);
  --shadow-floating: 0px 8px 20px rgba(39, 115, 95, 0.3);
  --shadow-overlay: 0px 16px 40px rgba(0, 0, 0, 0.14);
  --shadow-knob: 0px 1px 3px rgba(0, 0, 0, 0.2);
  --hairline-interactive: 1.5px solid rgba(36, 39, 43, 0.12);
  --hairline-card: 1px solid rgba(36, 39, 43, 0.07);
  --type-display-family: "DM Serif Display", Georgia, "Times New Roman", serif;
  --type-display-size: 32px;
  --type-display-weight: 400;
  --type-display-height: 1.2;
  --type-title-family: "DM Serif Display", Georgia, "Times New Roman", serif;
  --type-title-size: 26px;
  --type-title-weight: 400;
  --type-title-height: 1.25;
  --type-title-sm-family: "DM Serif Display", Georgia, "Times New Roman", serif;
  --type-title-sm-size: 22px;
  --type-title-sm-weight: 400;
  --type-title-sm-height: 1.25;
  --type-hero-numeral-family: "DM Serif Display", Georgia, "Times New Roman", serif;
  --type-hero-numeral-size: 56px;
  --type-hero-numeral-weight: 400;
  --type-hero-numeral-height: 1;
  --type-body-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --type-body-size: 16px;
  --type-body-weight: 400;
  --type-body-height: 1.5;
  --type-label-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --type-label-size: 13px;
  --type-label-weight: 600;
  --type-label-height: 1.4;
  --type-caption-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --type-caption-size: 13px;
  --type-caption-weight: 400;
  --type-caption-height: 1.4;
  --type-eyebrow-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --type-eyebrow-size: 12px;
  --type-eyebrow-weight: 700;
  --type-eyebrow-height: 1.4;
  --type-eyebrow-letter-spacing: 0.04em;
  --type-emphasis-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --type-emphasis-size: 15px;
  --type-emphasis-weight: 700;
  --type-emphasis-height: 1.4;
  --type-body-exam-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --type-body-exam-size: 17px;
  --type-body-exam-weight: 400;
  --type-body-exam-height: 1.5;
}

@media (prefers-color-scheme: dark) {
:root {
  --background: #16181A;
  --surface: #212426;
  --content-primary: #EEF0EE;
  --content-secondary: #9AA29E;
  --content-recessive: #C2C9C4;
  --accent: #7FC0AE;
  --on-accent: #13201C;
  --accent-tint: #24352F;
  --accent-deep: #9BD3C0;
  --chapter-tint2: #5F9384;
  --chapter-tint3: #456F60;
  --sand: #2C2823;
  --sand-content: #C9A86A;
  --neutral-tint: #2A2D2F;
  --success: #6FBF8F;
  --success-tint: #223328;
  --warning: #D9A84E;
  --warning-tint: #2E2A20;
  --warning-deep: #E6BE6C;
  --danger: #E08583;
  --danger-tint: #332222;
  --switch-track-off: #3A3E40;
  --switch-knob-off: #9AA29E;
  --disabled-fill: #2A2E30;
  --disabled-content: #6C736F;
  --shadow-raised: 0px 3px 12px rgba(0, 0, 0, 0.3);
  --shadow-floating: 0px 8px 20px rgba(0, 0, 0, 0.4);
  --shadow-overlay: 0px 16px 40px rgba(0, 0, 0, 0.18);
  --shadow-knob: 0px 1px 3px rgba(0, 0, 0, 0.35);
  --hairline-interactive: 1.5px solid rgba(238, 240, 238, 0.12);
  --hairline-card: 1px solid rgba(238, 240, 238, 0.07);
}
}

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

@font-face {
  font-family: "DM Serif Display";
  /* Served by the legal-site generator (web/generate.py copies it to /fonts);
     deliberately not bundled a second time here. */
  src: url("/fonts/DMSerifDisplay-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Device bezels: deliberate non-token literals. The light bezel is the ink
   #24272B (a phone body, not a text role); dark mode uses a LIGHTER #34383B
   plus a 1.5px inner highlight so the frame separates from dark cards instead
   of dissolving into them. Both approved as literals in the design review. */
:root {
  --bezel: #24272B;
  --bezel-ring: inset 0 0 0 1.5px rgba(255, 255, 255, 0);
  /* The page's own measure and its gutters, named once. Every full-width
     shell on the page (.topbar, .hero, .bento, .footer, the band, the why
     shell, .section-shell) is built from these two, and so is the width of
     the company's bar above the page: the dehaze bar's inner content lines
     up with the Scribe topbar's edges by ARITHMETIC now, not by two
     numbers that happened to look close. Change the measure here and the
     whole page, both brands' layers included, moves together. */
  --page-measure: 1400px;
  --page-gutter: clamp(16px, 4vw, 48px);
  /* --card-pad is the card's own padding, named so a panel that bleeds to
     the cell edges can negate it exactly. */
  --card-pad: clamp(20px, 3vw, 40px);
  /* Store badges: one shared height for two different aspect ratios, and the
     quarter-height clear space both vendors' guidelines require. Fixed px, not
     a clamp: a badge shrinking with the viewport would fall under Apple's 40px
     onscreen minimum. --badge-clear MUST stay --badge-height / 4. */
  --badge-height: 48px;
  --badge-clear: 12px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bezel: #34383B;
    --bezel-ring: inset 0 0 0 1.5px rgba(255, 255, 255, 0.1);
  }
}

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

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

body {
  margin: 0;
  background: var(--background);
  color: var(--content-primary);
  font-family: var(--type-body-family);
  font-size: var(--type-body-size);
  line-height: var(--type-body-height);
}

h1,
h2,
p,
ul,
figure,
blockquote {
  margin: 0;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

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

/* ---------- lockup ---------- */

.lockup {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.lockup-name {
  font-family: var(--type-title-family);
  font-size: 22px;
  line-height: 1.25;
  color: var(--content-primary);
}

.wave {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

.wave span {
  display: block;
  width: 4px;
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.wave span:nth-child(1) { height: 8px; }
.wave span:nth-child(2) { height: 16px; }
.wave span:nth-child(3) { height: 24px; }
.wave span:nth-child(4) { height: 12px; }
.wave span:nth-child(5) { height: 6px; }

.wave-img {
  width: 28px;
  height: auto;
}

/* ---------- shell ---------- */

.topbar,
.hero,
.bento,
.footer {
  max-width: var(--page-measure);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

.topbar {
  padding-top: var(--space-xl);
  padding-bottom: var(--space-sm);
}

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

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
  padding-top: clamp(32px, 7vh, 96px);
  padding-bottom: clamp(40px, 7vh, 96px);
}

.eyebrow {
  font-size: var(--type-eyebrow-size);
  font-weight: var(--type-eyebrow-weight);
  line-height: var(--type-eyebrow-height);
  letter-spacing: var(--type-eyebrow-letter-spacing);
  color: var(--accent);
  margin-bottom: var(--space-lg);
}

.hero-headline {
  font-family: var(--type-display-family);
  font-weight: var(--type-display-weight);
  /* Token display size is the 32px mobile floor; clamp scales it to desktop. */
  font-size: clamp(42px, 8.5vw, 104px);
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--content-primary);
  max-width: 12ch;
  text-wrap: balance;
}

.hero-sub {
  margin-top: clamp(20px, 3vw, 32px);
  font-size: clamp(17px, 1.6vw, 21px);
  line-height: 1.5;
  color: var(--content-secondary);
  max-width: 46ch;
}

.hero-note {
  margin-top: var(--space-xl);
  display: inline-block;
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--accent-deep);
  background: var(--accent-tint);
  border-radius: var(--radius-pill);
  padding: var(--space-sm) var(--space-lg);
}

/* The page's demo-content disclosure, above the fold. Caption type in the
   secondary ink, sitting with the hero copy: quiet enough to be read once and
   left behind, and deliberately not a pill (.hero-note above is the pill, and
   a badge would shout an aside). The only other statement of it is the
   closing "early" tile's sentence; no figure on the page carries a label. */
.hero-demo-note {
  margin-top: var(--space-lg);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
  max-width: 46ch;
}

/* ---------- device frames ----------
   Hero only: the full framed phone. Every other tile uses the crop-peek
   treatment (.device-crop) so the page reads as cards, not a phone museum.

   The FIGURE is the sized box and the query container; the picture inside
   it is always 100% wide. That inversion is the whole point: a corner
   radius in px does not scale, so a frame that shrank from 340px to 210px
   across the breakpoints kept a 44px corner and read, at the small end, as
   a lozenge rather than as a phone. In cqw the radius, the bezel wall and
   the screen's own corner are FRACTIONS of the frame, exactly as they are
   on a real device, and the frame stays the same object at every width.

   The ratios are calibrated so each treatment is byte-for-byte what it
   already was at its own full size, which is where the old fixed 44px was
   right: the hero frame at 340px (44 / 340 = 12.94%, 9 / 340 = 2.65%,
   36 / 340 = 10.59%) and the crop frame at its 260px desktop width
   (44 / 260 = 16.92%, 9 / 260 = 3.46%, 36 / 260 = 13.85%). Everything
   narrower than that now scales down with the frame instead of staying
   put. The two treatments keep their own ratios rather than sharing one,
   because sharing would have meant changing a width that was already
   correct. */

.device {
  container-type: inline-size;
  width: min(300px, 78vw);
  margin-inline: auto;
  --device-radius: 12.94cqw;
  --device-bezel: 2.65cqw;
  --device-screen-radius: 10.59cqw;
}

.device picture {
  display: block;
  width: 100%;
  background: var(--bezel);
  border-radius: var(--device-radius);
  padding: var(--device-bezel);
  box-shadow: var(--bezel-ring), var(--shadow-raised);
}

.device img {
  width: 100%;
  aspect-ratio: 393 / 852;
  object-fit: cover;
  border-radius: var(--device-screen-radius);
}

.hero-device {
  width: min(340px, 78vw);
}

/* Crop-peek: the frame rises from the card bottom and the card radius clips
   it. The padding-top is the breathing room between the tile's copy and the
   phone. Cards using it must keep padding-bottom 0 + overflow hidden. */

.device-crop {
  container-type: inline-size;
  margin-top: auto;
  margin-inline: auto;
  width: min(240px, 82%);
  display: flex;
  flex-direction: column;
  padding-top: var(--space-xl);
  --device-radius: 16.92cqw;
  --device-bezel: 3.46cqw;
  --device-screen-radius: 13.85cqw;
}

.device-crop picture {
  display: block;
  width: 100%;
  background: var(--bezel);
  border-radius: var(--device-radius) var(--device-radius) 0 0;
  padding: var(--device-bezel) var(--device-bezel) 0;
  box-shadow: var(--bezel-ring), var(--shadow-raised);
}

.device-crop img {
  width: 100%;
  aspect-ratio: 375 / 400;
  object-fit: cover;
  object-position: top;
  border-radius: var(--device-screen-radius) var(--device-screen-radius) 0 0;
}

/* ---------- bento grid ---------- */

.bento {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  padding-bottom: clamp(48px, 6vw, 96px);
}

.card {
  background: var(--surface);
  border: var(--hairline-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
  padding: var(--card-pad);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  overflow: hidden;
}

/* Hover lift: only for devices that actually hover, and only when motion is
   welcome. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .card {
    transition: transform 200ms ease;
  }

  .card:hover {
    transform: translateY(-3px);
  }
}

.tile-headline {
  font-family: var(--type-title-family);
  font-weight: var(--type-title-weight);
  font-size: clamp(26px, 2.4vw, 34px);
  line-height: 1.15;
  color: var(--content-primary);
  max-width: 24ch;
  text-wrap: balance;
}

.tile-headline-xl {
  font-size: clamp(30px, 3.4vw, 52px);
  line-height: 1.08;
}

.tile-body {
  margin-top: var(--space-md);
  color: var(--content-secondary);
  max-width: 58ch;
}

/* The two treatments that end ON the card's bottom edge: the crop-peek phone
   and the key-facts sheet. Both need the card's own bottom padding gone, so
   the edge that cuts them is the card's. */
.tile-crop,
.tile-sheet {
  padding-bottom: 0;
}

/* ---------- tinted cards (AA tint pairing: text on accentTint is
   accent/accentDeep, on sand is sandContent, on neutralTint is
   contentPrimary; never contentSecondary on a tint) ---------- */

.card-tint {
  background: var(--accent-tint);
}

.card-tint .tile-headline,
.card-tint .tile-body,
.card-tint .stat-title,
.card-tint .stat-value,
.card-tint .stat-label,
.card-tint .stat-body {
  color: var(--accent-deep);
}

.card-tint .eyebrow {
  color: var(--accent);
}

.card-sand {
  background: var(--sand);
}

.card-sand .eyebrow,
.card-sand .tile-headline,
.card-sand .tile-body {
  color: var(--sand-content);
}

/* ---------- stat tiles ---------- */

.tile-stat {
  justify-content: space-between;
  gap: var(--space-sm);
}

.stat-title {
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--content-secondary);
  text-wrap: balance;
}

.stat-value {
  font-family: var(--type-display-family);
  font-weight: var(--type-display-weight);
  font-size: clamp(56px, 7vw, 96px);
  line-height: 1;
  color: var(--accent);
  margin-block: var(--space-sm-md);
}

.stat-word {
  font-size: clamp(40px, 4.6vw, 60px);
}

.stat-unit {
  font-size: 0.35em;
}

.stat-label {
  font-size: 15px;
  line-height: 1.4;
  color: var(--content-secondary);
  max-width: 30ch;
}

.stat-body {
  margin-top: var(--space-md);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
  max-width: 34ch;
}

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

.footer {
  border-top: var(--hairline-card);
  padding-top: clamp(32px, 4vw, 48px);
  padding-bottom: clamp(40px, 5vw, 64px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(28px, 4vw, 44px);
  align-items: end;
  /* The mark is cut by the page's own edge; the page never scrolls for it. */
  overflow: hidden;
}

.footer-copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm-md);
  align-items: flex-start;
}

.footer .lockup {
  margin-bottom: var(--space-sm);
}

.footer-line {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
}

.footer-links {
  margin-top: var(--space-md);
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

.footer-links a {
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------- 6-column bento (tablet and up) ---------- */

/* The grid's AREA MAPS are not here: they are data in the site file
   (bento.layout) and generate.py appends them, generated and validated, after
   this static kit sheet (see grid_css). What stays here is everything about a
   cell that is true in ANY arrangement; a map's judgement calls - which rows
   pair, where the splits fall, what breaks headlines at 222px a cell - travel
   with the map, in the site file that chose it. */
@media (min-width: 720px) {
  .bento {
    gap: 20px;
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .tile-center {
    justify-content: center;
  }

  .tile-stat {
    min-height: 240px;
  }

  /* Trio and visits: text on top, crop-peek phone pinned to the card bottom.
     The width is set on the FIGURE, which is the frame's query container, so
     the bezel and both corner radii follow it (see "device frames"). */
  .tile-crop .device-crop {
    width: min(230px, 82%);
  }

  /* Crop-edge tuning, per shot: the shared 375/400 cut (source row 960 of
     the 900px-wide captures) slices through UI text on three shots. Each
     override moves that cut a few percent so it lands in the whitespace
     between UI rows (verified against the capture's row histogram and by
     screenshot). Phone widths keep the shared 375/330 cut: at that height
     all four shots already cut in whitespace. */
  .device-crop.shot-summary img {
    aspect-ratio: 375 / 432;
  }

  .device-crop.shot-visits img {
    aspect-ratio: 375 / 414;
  }

  .device-crop.shot-transcript img {
    aspect-ratio: 375 / 396;
  }

}

/* ---------- hero side-by-side + wider gutters (desktop) ---------- */

@media (min-width: 1100px) {
  .hero {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    min-height: min(calc(100vh - 96px), 860px);
    padding-top: var(--space-xl);
  }

  /* The hero's second column is the STAGE now, and it stretches: the phone
     keeps its own width and centres itself inside it (.device), and the
     payoff cards need the full column as their coordinate space, because
     they are positioned against the phone's centre line. */

  .bento {
    gap: 24px;
  }

  .tile-crop .device-crop {
    width: min(260px, 74%);
  }

  .tile-comp-bleed .tile-headline {
    max-width: none;
  }
}

/* ---------- phone-width page-length discipline ---------- */
/* Shorter crops and tighter stat tiles at a hand's width: the story is the
   same, the scroll is not. */

@media (max-width: 719px) {
  .bento {
    gap: 12px;
  }

  .device-crop {
    width: min(210px, 74%);
  }

  .device-crop img {
    aspect-ratio: 375 / 330;
  }

  .stat-value {
    margin-block: var(--space-sm);
  }

  .tile-stat {
    min-height: 0;
  }

  .hero-device {
    width: min(260px, 74vw);
  }
}

/* ---------- app elements as cells ----------
   Real app components, transparent-backed, sitting directly on the tile
   surface: the grid cell reads as a place the app's own UI turned up rather
   than as a card describing it. These sections come AFTER the base .card /
   .tile-* rules and their media queries on purpose: they refine those rules,
   so they have to win the cascade. */

.app-el {
  align-self: stretch;
  width: auto;
  margin-top: auto;
  padding-top: var(--space-xl);
  display: flex;
  flex-direction: column;
}

.app-el picture {
  display: block;
  width: min(444px, 100%);
  margin-inline: auto;
}

/* The scrubber is a timeline: it wants the whole cell, not a centred column. */
.app-el-wide picture {
  width: 100%;
}

/* The answer arrives from the app: let the bubble run out to the cell edge.
   Negating --card-pad is exactly why the card's padding is a named property. */
.app-el-bleed {
  margin-inline: calc(-1 * var(--card-pad));
}

.app-el-bleed picture {
  width: 100%;
}

.app-el img {
  width: 100%;
}

/* ---------- the key facts, as a sheet ----------
   The to-do list lies on the cell like any other cut-out, and the key facts
   arrive over it the way they arrive in the app: as a bottom sheet, rising
   from the card's own bottom edge, cut by it, with its grabber showing.

   The chrome is not drawn here, and that is the point. The cut-out IS the
   app's sheet, rendered by the app's own ScribeSheet scaffold: the paper
   ground, the card hairline, --radius-lg on the top two corners only, and
   the design system's 36x5 handle are all inside the artwork. Anything this
   stylesheet added around it would be a second sheet drawn around the first,
   which is exactly what the first version of this rule did. The page's job
   is only to put it where a sheet goes and let the card's overflow cut it.

   Both cut-outs in this cell keep ONE measure, so the app's own type is at
   one scale in one cell: the sheet is not wider than the checklist above it.
   A sheet that spanned the whole four-column cell would draw the same panel
   at twice the scale of the card above it, and the two would read as two
   different apps.

   How much of the panel shows is a fraction of the ARTWORK, not a pixel
   count: the picture box carries the aspect ratio and clips, so the same top
   of the same panel is visible at 360px and at 1440px and the title and its
   first rows can never be what falls below the edge. Both locales' renders
   are the same panel at the same scale, so one ratio serves both (1485 rows
   in English, 1521 in Portuguese; the top 700 is the title, the AI-summary
   caption and the first facts either way). */

.app-sheet {
  align-self: stretch;
  width: auto;
  margin-top: clamp(16px, 2vw, 26px);
}

.app-sheet picture {
  display: block;
  width: min(444px, 100%);
  margin-inline: auto;
  aspect-ratio: 1332 / 700;
  overflow: hidden;
}

.app-sheet img {
  width: 100%;
}

/* ---------- store badges (third-party artwork, unmodified) ----------
   Apple's and Google's badge artwork ships byte-verbatim from vendor/ and is
   never restyled here: no filter, opacity, border, background, transform or
   overlay may touch .store-badge img. The stylesheet's whole job is to give the
   artwork the size and the clear space the guidelines demand.

   --badge-height is one height for both badges (equal HEIGHT, never equal
   width: the aspect ratios differ and neither may be scaled non-uniformly).
   48px clears Apple's 40px onscreen minimum and Google's 28px with room to
   spare. --badge-clear is exactly one quarter of it, the minimum clear space
   both vendors require, applied as each badge box's own padding so that
   nothing (the sticker, the other badge, the copy) can enter it. The row gap
   adds to that padding rather than replacing it, so the artwork keeps at least
   its quarter-height margin however the row wraps. */

.store-badges {
  margin-top: clamp(14px, 1.8vw, 22px);
  /* Cancel the first badge's own clear-space padding so the row lines up
     optically with the tile copy above it. The outer-left clear space is then
     the card's own padding, which is empty and never smaller than --card-pad's
     20px floor: comfortably more than the 12px quarter-height the guidelines
     ask for at the largest badge size on the page. */
  margin-inline-start: calc(-1 * var(--badge-clear));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--badge-clear);
}

/* The two badges are one group, so the sticker can move to its own line
   without ever splitting the pair. Each badge box already carries its own
   quarter-height clear space, so two adjacent boxes leave half a badge height
   of empty space between the artwork with no gap of their own; wrap is the
   graceful fallback if a cell ever gets narrower than the pair. */
.store-badge-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.store-badge {
  display: block;
  padding: var(--badge-clear);
}

.store-badge img {
  height: var(--badge-height);
  /* auto, so the width follows each badge's own aspect ratio. */
  width: auto;
  max-width: 100%;
}

/* The availability signal, in the page's own tokens, BESIDE the artwork and
   outside its clear space. It exists because greying, dimming or stamping the
   badges themselves is a prohibited modification. */
.store-sticker {
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--accent-deep);
  background: var(--accent-tint);
  border-radius: var(--radius-pill);
  padding: var(--space-sm) var(--space-lg);
}

/* Store badges at a hand's width. This block sits AFTER the base rules above
   on purpose: a media query adds no specificity, so the phone overrides only
   win by coming later (the same reason this whole section follows the .card
   rules). At 48px the pair no longer fits one line inside a phone-width card
   and the row broke as "Apple alone / Google plus sticker", which reads like
   an accident. 40px is exactly Apple's onscreen minimum and well over
   Google's 28px, it keeps the two badges together, and --badge-clear stays
   exactly a quarter of it. Uniform scaling only: the height moves, the
   artwork's aspect ratio does not. The sticker then takes its own line by
   rule rather than by luck. */

@media (max-width: 719px) {
  :root {
    --badge-height: 40px;
    --badge-clear: 10px;
  }

  .store-badges {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-sm);
  }

  .store-sticker {
    margin-inline-start: var(--badge-clear);
  }
}

@media (min-width: 720px) {
  /* A wide component tile (the player) is a short cell stretched by its
     neighbour: let the copy and the timeline sit together as one centred
     group instead of drifting to opposite ends of the cell. Keyed to the
     tile's own treatment class, not to an arrangement's area name. */
  .tile-comp-wide {
    justify-content: center;
  }

  .tile-comp-wide .app-el {
    margin-top: 0;
    padding-top: clamp(28px, 3.4vw, 48px);
  }
}

/* ===================================================================== *
 * Imagery pass: the waveform band and the macro crops.
 * Appended after every base rule AND its media
 * queries on purpose, for the same cascade reason as the app-element
 * section above: these refine .card / .tile-* / .footer rules that the
 * blocks before them establish.
 * ===================================================================== */

/* ---------- the waveform band ----------
   A full-bleed editorial moment, and since the 2026-08-31 reorder it opens
   the feature section rather than following the hero: the type sits in the
   page's own measure, the waveform runs past BOTH viewport edges so the
   recording reads as longer than the page. The band carries no fill of its
   own, so it never lands a second coloured slab next to the accent-tinted
   consent card below it - nor against the memory band, which the section
   heading now separates it from. The overflow is contained HERE, not by the
   document, which is what keeps scrollWidth == clientWidth.

   THE TOP PADDING IS THE MOVE'S ONE SPACING DECISION. Under the hero the band
   needed almost none (it was 4-10px): the hero's own bottom padding already
   held it off a photograph. Under the section heading it is display serif
   against display serif - "Scribe keeps the visit." in two lines, then this
   band's eyebrow and its own larger headline - and at 4px the eyebrow read as
   a third line of the heading above it rather than as the start of something
   new. Rendered at 390, 768 and 1440 in both themes and both locales before
   the change and after it. The step is the section's own (the same ladder
   .bento-head uses), so the heading now has 56-100px under it, a little more
   than the 44-67px the hero used to give the band, which is right: two
   headings need more air between them than a picture and a heading do.
   Nothing else moved; the bottom padding is untouched. */

.band-wave {
  overflow: hidden;
  padding-top: clamp(30px, 3.4vw, 56px);
  padding-bottom: clamp(32px, 5vw, 76px);
}

.band-wave-inner {
  max-width: var(--page-measure);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

.band-headline {
  font-family: var(--type-display-family);
  font-weight: var(--type-display-weight);
  font-size: clamp(32px, 5.4vw, 76px);
  line-height: 1.06;
  letter-spacing: -0.01em;
  color: var(--content-primary);
  max-width: 20ch;
  text-wrap: balance;
}

/* The consent ask, as the band's body. Body measure, not display type: the
   headline is the band's voice and this is the sentence under it, so it takes
   the page's reading size and a 58ch measure like every tile body. Its own
   margin (rather than the headline's) keeps the two apart, because the
   headline is shared with the stacked layout below 1100px. */
.band-body {
  margin-top: clamp(14px, 1.8vw, 24px);
  color: var(--content-secondary);
  max-width: 58ch;
}

/* The sound itself. Not a picture of a level meter: the real meter, drawn by
   the page from the committed recording, one span per 50 ms frame.

   GEOMETRY. Everything is a ratio of the band's height, and the ratios are
   LevelMeter's own (app/lib/ui/widgets/level_meter.dart): a 5px bar and a 4px
   gap in a 52px meter, corner radius 3. So --wave-unit is one of the widget's
   pixels at this band's scale and the band is the recorder's meter enlarged,
   not a lookalike drawn to taste. The ink is --danger, the tone the recorder
   passes while capture is running.

   THE BARS BOUNCE, they do not slide. Each bar is laid out at the meter's full
   height and scaled from its BOTTOM edge, because LevelMeter draws every bar up
   from the meter's baseline; its scale and its opacity are the level and the
   painter's 0.4 -> 1.0 ramp. A bar's resting values come from its own level
   class at the end of this stylesheet, and while the animation runs they come
   from the one generated keyframes there, which walks the whole recording a
   frame at a time. Bar i is i frames ahead of bar i-1 (a negative delay, also
   generated), so the values still travel leftward along the row exactly as they
   leave the recorder's window - but the motion a reader sees is what the
   recorder shows: amplitude, changing in place, twenty times a second.

   THE CLIP WINDOW. .wave-art is the window and it clips; .wave-row holds one
   bar per frame of the whole recording, far wider than any viewport, so the
   recording's own first and last bar are off screen and the band reads as a
   window onto something longer rather than as a graphic with two ends. */

.wave-art {
  --wave-h: clamp(104px, 15vw, 190px);
  --wave-unit: calc(var(--wave-h) / 52);
  --wave-bar: calc(5 * var(--wave-unit));
  --wave-gap: calc(4 * var(--wave-unit));
  --wave-radius: calc(3 * var(--wave-unit));
  /* The recorder's own clock: --wave-frame is the sample interval the app
     meters at, and one pass over the recording is every frame of it once. Real
     speed, not a slowed-down quarter: at the app's cadence the band IS the
     working meter, which is the only thing this band claims to be. */
  --wave-cycle: calc(var(--wave-bars) * var(--wave-frame));
  margin-top: clamp(14px, 2.2vw, 30px);
  /* Full bleed through both gutters: the containing block is the band's own
     centred content box, so half its width less half the viewport's is
     exactly the distance to each page edge. */
  margin-inline: calc(50% - 50vw);
  height: var(--wave-h);
  overflow: hidden;
}

/* The row never moves, so nothing here has to survive being translated: no
   period arithmetic, no laid-out-width correction, no copies. The trailing
   margin (rather than the flex container's `gap`) stays, so the row ends past
   the last bar's gap and the pitch is uniform for every bar including the
   last. */
.wave-row {
  display: flex;
  width: max-content;
  height: 100%;
}

.wave-row span {
  flex: none;
  width: var(--wave-bar);
  height: 100%;
  margin-inline-end: var(--wave-gap);
  border-radius: var(--wave-radius);
  background: var(--danger);
  /* LevelMeter is bottom-aligned: a bar grows up from the baseline. */
  transform-origin: bottom;
}

/* The keyframes, the timing and the per-bar phases are GENERATED from the
   recording and appended at the end of this stylesheet, next to the resting
   level classes they override. Under prefers-reduced-motion there is no
   animation at all: the bars simply stand at the recording's first moment.

   Time, not scroll. A recorder's meter is alive whether or not the page is
   moving, so the band runs on its own clock; the earlier scroll-driven pass
   (the band's passage through the viewport as the timeline) is gone with the
   strip it scrubbed, because scrubbing a bounce means the bars only bounce
   while a finger is moving, which is the opposite of what a meter is. */

/* ---------- macro crops ----------
   Extreme close-ups of real app UI, anchored off-centre so a CELL EDGE crops
   them. One rule holds everywhere: a cut may only land in whitespace or flat
   fill, never through a line of UI text. */

.macro {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.macro picture {
  display: block;
}

.macro img {
  max-width: none;
}

/* Offline: the record button's rings, blown up and anchored in the cell's
   BOTTOM-END corner, bleeding out through the card's right edge and its
   bottom edge at once.

   The artwork is square (2034 x 2034) and its top-left two thirds on both
   axes are the whole halo stack: the outer ring is tangent to the top and
   the left edge, the disc centre and the mic glyph sit at 1/3, and the
   glyph's own box ends at 41%. So the crop and this anchoring are one
   contract, documented in the README and cut for exactly this geometry
   (export_marketing_macros_test.dart, _haloCropFactor): the corner keeps the
   image's TOP-LEFT region, the transparent bleed past two thirds leaves the
   card for free, and the cut itself has to be pushed IN far enough to reach
   the ink, or the bleed absorbs the whole gesture.

   --halo-keep is that contract's number: the fraction of each axis that stays
   inside the card. It sits at the contract's FLOOR, 0.45, and the floor is
   where it belongs. At 0.6 the cut landed at 60% of the image, which is past
   the disc's own edge at 55.8%: nothing but transparent bleed and the outer
   ring's last hair left the card, the disc stood whole and the cell read as a
   card with a button parked in it rather than a cell that cropped a picture.
   At 0.45 the two cuts pass through the disc (measured: the disc spans 10.9%
   to 55.8% of the axis, centred at 33.4%), so a real quarter of it is gone
   through both the bottom and the end edge and the bento box is visibly what
   cropped it - while the mic glyph, whose box ends at 41%, keeps its whole
   silhouette with 4% of the image to spare. Below 45% that clearance is gone
   and the cut runs through the glyph, which reads as a rendering fault rather
   than a crop; that is why the floor is a floor. Move the anchor and the crop
   has to move with it. */
.macro-halo {
  --halo: clamp(184px, 21vw, 290px);
  --halo-keep: 0.45;
  margin-top: auto;
  padding-top: clamp(10px, 1.4vw, 18px);
  /* The artwork takes the cell's bottom-END corner: align-items keeps the
     picture at its own width instead of stretching it, so the negative end
     and bottom margins below are what carry it out through the card's two
     edges. */
  align-items: flex-end;
}

.macro-halo picture {
  margin-inline-end: calc(-1 * var(--card-pad)
                          - (1 - var(--halo-keep)) * var(--halo));
  margin-bottom: calc(-1 * var(--card-pad)
                      - (1 - var(--halo-keep)) * var(--halo));
}

.macro-halo img {
  width: var(--halo);
}

/* ---------- brand mark at scale ----------
   The wave half of the lockup, large and quiet, sitting on the footer's
   baseline and cut by the page edge: the mark keeps going where the page
   stops. Bars only, so the cut can never land in a word. Ink in light,
   chalk in dark, both from the shipped mark pair; with the marks absent
   the markup carries no mark at all and these rules match nothing. */

.footer-mark {
  /* One named width so the overhang can be a fraction of the MARK rather than
     a pixel count: the cut then stays proportional at every viewport. 196px is
     the ceiling on purpose; at 260 the chalk mark shouted in the dark theme. */
  --mark-width: clamp(112px, 15vw, 196px);
  justify-self: end;
  /* Out through the page's own gutter, plus a slice of the mark: the wave
     keeps going where the page stops. The clamp repeats the shell's
     padding-inline because that IS the page edge here. */
  margin-inline-end: calc(-1 * var(--page-gutter) - 0.16 * var(--mark-width));
}

.footer-mark picture {
  display: block;
}

.footer-mark img {
  width: var(--mark-width);
  max-width: none;
}

@media (min-width: 720px) {
  .footer {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}

/* Desktop: the words hold the page's own measure on the left and the sound
   runs off the right edge, which is the band's whole argument in one line.
   Below 1100px the two stack and the wave bleeds through BOTH gutters
   instead, so the band never turns into a centred graphic. */
@media (min-width: 1100px) {
  .band-wave-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    align-items: center;
    column-gap: clamp(24px, 3vw, 56px);
  }

  /* The window starts at its own column and runs to the page edge: the right
     gutter, plus whatever the viewport is wider than the page's measure. Any
     overshoot (a scrollbar's width, say) is eaten by the band's own overflow,
     so this can only ever be too long, never too short. The start margin goes
     back to zero, because on this layout the copy is what holds the left. */
  .wave-art {
    margin-top: 0;
    margin-inline-start: 0;
    margin-inline-end: calc(-1 * (var(--page-gutter)
                       + max(0px, (100vw - var(--page-measure)) / 2)));
  }
}

/* ===================================================================== *
 * The merge: the sections the page grew around the bento.
 *
 * personas and the memory band come between the hero and the feature
 * section (whose own opener is the waveform band); the questions, the
 * waitlist and this page's own legal texts come after the grid.
 * Appended after every base rule AND its media queries, for the same
 * cascade reason as the two sections above: a few of these refine .card,
 * .hero-headline, .footer-links and .eyebrow, and refinements have to
 * win. Nothing above this line was edited.
 *
 * Colour follows the page's tint pairing exactly: text on accentTint is
 * accent/accentDeep, on neutralTint it is contentPrimary or the recessive
 * ink, never contentSecondary on a tint. Two full-bleed bands carry the
 * two new grounds and they are far apart on the page, so no two coloured
 * slabs are ever adjacent. No gradients anywhere.
 * ===================================================================== */

/* The reset above covers h1, h2 and p; these sections add h3 and h4 (the
   persona and FAQ headings, the legal blocks) and the form elements. */
h3,
h4,
fieldset,
input,
button {
  margin: 0;
}

/* ---------- shared: the page shell, and the paired display heading ---------- */

/* The same measure and gutters as .hero / .bento / .footer, for a section
   that is not one of them. */
.section-shell {
  max-width: var(--page-measure);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

/* A paired heading is ONE heading with two lines: a statement and its turn.
   The turn takes the quieter ink, which is what makes it read as a second
   beat rather than as a second heading. */
.line-b {
  display: block;
  color: var(--content-secondary);
}

.section-headline {
  font-family: var(--type-display-family);
  font-weight: var(--type-display-weight);
  font-size: clamp(30px, 3.9vw, 54px);
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: var(--content-primary);
  max-width: 24ch;
  text-wrap: balance;
}

/* The split: a heading that stays with its column, and the reading matter
   beside it. One column at a hand's width, two once there is room, so the
   questions, the form and the legal appendix each hold a real measure
   instead of a 68ch ribbon down the left of a 1400px page. */
.split-body {
  margin-top: clamp(26px, 3.2vw, 44px);
}

/* The hero headline is a pair now, so it gives back some of the size it
   carried as a single line: four lines at 104px would have pushed the sub,
   the button and the demo note off every laptop screen. */
.hero-headline {
  font-size: clamp(36px, 5.6vw, 72px);
  max-width: 18ch;
}

/* ---------- the call to action ----------
   Scribe green, everywhere inside the product's own layer. The company's own
   button up in the bar is dehaze's near-black, and it is the only control on
   the page that is not this green. */

.cta-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--accent);
  color: var(--on-accent);
  border: 0;
  border-radius: var(--radius-pill);
  padding: 15px 28px;
  font-family: var(--type-label-family);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.005em;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

@media (hover: hover) {
  .cta-button:hover {
    background: var(--accent-deep);
  }
}

/* Scribe's own controls take Scribe's own focus ring; the company pill up in
   the strip takes dehaze's lavender, on dehaze's own control. */
.cta-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.hero-cta {
  margin-top: clamp(22px, 2.8vw, 32px);
}

/* ---------- the hero's payoff cards ----------
   Three small surfaces carrying the hero's three beats: what came back, what
   to do next, who it went to. They are the page's own card language at a
   quarter scale (surface, hairline, radius, the raised shadow), and they are
   demo content of the same kind as the screenshot they lie against, which the
   hero's demo-content line already covers.

   FLOW FIRST, FLOAT LAST. The default is a stack under the phone: it cannot
   cover the screen, cannot overflow, grows with a reader's own text size and
   prints. Only from 1240px up, where the hero splits into two columns AND the
   phone column has real slack beside it, do the cards lift onto the phone's
   left edge. That threshold is arithmetic, not taste: at 1240 the copy column
   is 1.35fr of a 1144px measure, the cards need 320px to the left of the
   phone's centre, and the hero's own gutter absorbs what the column cannot -
   below it they would either sit off the phone or land on the headline.

   The three tops (26 / 40 / 54 percent) are read off the home screenshot, in
   BOTH locales: the stack stands in the band that runs from under the date to
   above the record button's caption, which is where that screen holds nothing
   but the halo. It clears the greeting and the date at the top, and it clears
   the consent caption under the record button - the one line on that screen
   this page may not cover, and the line that wraps to two in Portuguese. What
   it does lie over is the halo, which is a gradient. */

.hero-stage {
  position: relative;
}

.hero-cards {
  list-style: none;
  margin: clamp(16px, 2.2vw, 24px) auto 0;
  padding: 0;
  width: min(340px, 78vw);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.hero-card {
  background: var(--surface);
  border: var(--hairline-card);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-raised);
  padding: 12px 16px;
}

.hero-card-label {
  display: block;
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--accent);
}

.hero-card-text {
  display: block;
  margin-top: 3px;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-primary);
}

/* Standing under the phone, the stack takes the phone's own width, and the
   hero narrows the phone at a hand's width. Two boxes of different widths on
   one centre line read as a mistake. This override lives HERE, next to the
   width it overrides, because the section it would otherwise sit in (the
   page-length discipline block) comes earlier in the sheet and would lose. */
@media (max-width: 719px) {
  .hero-cards {
    width: min(260px, 74vw);
  }
}

@media (min-width: 1240px) {
  /* The list becomes the phone's own coordinate space: it takes the stage's
     box, so a card's `top` is a fraction of the phone's height, and it takes
     no pointer events, so nothing floating here can swallow a click meant for
     the button beside it. */
  .hero-cards {
    position: absolute;
    inset: 0;
    margin: 0;
    width: auto;
    display: block;
    pointer-events: none;
  }

  /* Anchored to the phone's centre line, not to the column: the card's right
     edge lands 112px left of centre, which is 58px onto a 340px phone. They
     clip the screen's edge and hang off it; they never lie across it. */
  .hero-card {
    position: absolute;
    inset-inline-end: calc(50% + 112px);
    width: 208px;
  }

  .hero-card:nth-child(1) { top: 26%; }
  .hero-card:nth-child(2) { top: 40%; }
  .hero-card:nth-child(3) { top: 54%; }
}

/* ---------- the feature grid's heading ----------
   The bento had no heading of its own and the page went from the memory
   statistic straight into cards. This is the section's name in the same
   paired-display treatment personas and the waitlist use, and it is the
   grid's ACCESSIBLE name too (aria-labelledby), which is why the grid no
   longer carries an aria-label: one section, one name. The air above it is
   the memory band's own bottom margin; only the space down to what follows
   is set here - the waveform band since the 2026-08-31 reorder, and through
   it the grid. */
.bento-head {
  margin-bottom: clamp(26px, 3.2vw, 44px);
}

/* ---------- personas ----------
   Three scenarios in the bento's own card language, so the section reads as
   part of the same page rather than as a strip bolted above it: same surface,
   same hairline, same radius, same padding, the same gap ladder as the grid
   below (12 / 20 / 24). */

.personas {
  padding-top: clamp(36px, 5vw, 76px);
}

.persona-row {
  margin-top: clamp(26px, 3.2vw, 44px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

/* Category, then status, both on the left edge. The two were a justified row
   for one round; Portuguese sets the category half again as long ("PARA UM PAI
   OU UMA MAE DE QUEM VOCE CUIDA") and pushed the chip onto its own line
   anyway, so the stack is what the page actually renders in one of its two
   languages. Making it the rule in both is the difference between a layout
   and a coincidence. */
.persona-top {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-md);
}

/* The eyebrow's own bottom margin belongs to a stacked heading, not to a row. */
.persona-top .eyebrow {
  margin-bottom: 0;
}

/* The chip does the status work, and its colour role is data (status_kind),
   not a match on the label's words: "In the waitlist beta" is the accent
   tint with its deep ink, "Planned" the neutral tint with the page's primary
   ink. Both are the pairings the tinted cards below already use. */
.persona-status {
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  border-radius: var(--radius-pill);
  padding: 6px 14px;
}

.status-beta {
  background: var(--accent-tint);
  color: var(--accent-deep);
}

.status-planned {
  background: var(--neutral-tint);
  color: var(--content-primary);
}

.persona-headline {
  margin-top: clamp(24px, 2.8vw, 36px);
  font-family: var(--type-title-family);
  font-weight: var(--type-title-weight);
  font-size: clamp(23px, 1.9vw, 29px);
  line-height: 1.16;
  color: var(--content-primary);
  max-width: 20ch;
  text-wrap: balance;
}

/* Two lines reserved wherever the cards stand side by side, because two of the
   three headlines take two lines in both languages and the third does not:
   without the reserve the three bodies start at three different heights and the
   trio reads as three unrelated cards. In lines, not pixels, so it follows the
   clamp. Stacked, there is nothing to align to and the reserve would only add
   a gap.

   The KICKER above it needs the same reserve for the same reason, and the
   .persona-top comment already names the offender: Portuguese sets the third
   card's category as "PARA UM PAI OU UMA MAE DE QUEM VOCE CUIDA", which wraps
   to two lines between 1100 and about 1360px while the other two stay on one.
   Reserving the headline alone left that whole card's chip, headline and body
   sitting a label-line lower than its neighbours across that entire range.
   Two label lines, in ems so it follows the label's own line-height. */
@media (min-width: 1100px) {
  .persona-top .eyebrow {
    min-height: calc(2 * var(--type-label-height) * 1em);
  }

  .persona-headline {
    min-height: 2.32em;
  }
}

.persona-body {
  margin-top: var(--space-md);
  font-size: 16px;
  line-height: 1.55;
  color: var(--content-secondary);
  max-width: 62ch;
}

/* ---------- the memory band ----------
   The one statistic on the page, and its only external citation. A flat
   neutral ground, no artwork, no chart: the section's whole job is to be
   believed, and an infographic would argue with the evidence it quotes. The
   figure is lifted out of the sentence in the brand serif rather than set as
   a separate numeral, so the number the reader sees is the number the
   sentence says, in the sentence's own grammar. */

/* The band is a slab of tint on the page's paper, so the air above and below
   it is the same air: the same margin on both sides, or the bento's first row
   crowds a ground it is not part of. It had a top margin and no bottom one,
   which read as the evidence being glued to the cells that follow it. */
.why-band {
  margin-block: clamp(40px, 5vw, 76px);
  background: var(--neutral-tint);
  padding-block: clamp(44px, 6vw, 92px);
}

.why-shell {
  max-width: var(--page-measure);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(24px, 3vw, 40px);
}

.why-headline {
  font-family: var(--type-display-family);
  font-weight: var(--type-display-weight);
  font-size: clamp(28px, 3.3vw, 46px);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--content-primary);
  max-width: 20ch;
  text-wrap: balance;
}

/* contentSecondary is not an ink for a tint (AA), so the recessive ink takes
   its place on this ground: 6.7:1 in light, and the token is AA-checked on
   the dark ramp. */
.why-headline .line-b {
  color: var(--content-recessive);
}

.why-body {
  font-size: clamp(17px, 1.4vw, 20px);
  line-height: 1.6;
  color: var(--content-recessive);
  max-width: 48ch;
}

/* The figure takes its own line inside its own sentence. It was set inline
   at 1.9em for one round and rendered badly in both languages: the phrase
   broke across two lines of body copy and dragged the leading with it, in
   English at 1440 and worse in Portuguese, which sets it a fifth longer.
   A block gives it the stat tiles' weight, keeps the sentence's grammar and
   reading order intact, and can never overflow, because a block of text
   wraps at its spaces. */
.why-figure {
  display: block;
  margin-block: clamp(8px, 0.9vw, 14px) clamp(4px, 0.5vw, 8px);
  font-family: var(--type-display-family);
  font-weight: var(--type-display-weight);
  font-size: clamp(34px, 4vw, 58px);
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--accent);
}

/* The reference gets its OWN measure, not the body's. 56ch is a reading
   measure and this is a single reference of about 96 characters, so the cap
   broke it mid-journal-name ("J R Soc / Med. 2003;96(5):219-222.") at every
   desktop width, which is exactly how a careless citation looks. A reference
   is a label: it wants to sit on one line where the column allows and to
   break at a sensible place where it does not, which is what text-wrap:
   pretty is for. */
.why-citation {
  margin-top: clamp(16px, 1.8vw, 24px);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-recessive);
  max-width: 104ch;
  text-wrap: pretty;
}

/* The page's one outbound link: the reference itself is the link, underlined
   at rest because a citation that does not look followable is not doing its
   job. It keeps the recessive ink of its line and takes the accent on
   interaction only, so the band stays quiet.

   THE UNDERLINE WHISPERS. At full-strength currentColor and from-font
   thickness the line read as a raw browser hyperlink dropped into a quiet
   band; a citation's rule should sit under the words, not shout from them.
   So: a hairline, and ink at a bit over a third of the text's. The plain
   currentColor declaration stays as the fallback an engine without color-mix
   falls back to, which is the underline this line had before. Reaching the
   link - pointer or keyboard - brings both the text and its rule to full
   accent, so the affordance is unmistakable the moment it is addressed. */
.why-citation-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: currentColor;
  text-decoration-color: color-mix(in srgb, currentColor 38%, transparent);
  transition: color 140ms ease, text-decoration-color 140ms ease;
}

.why-citation-link:hover,
.why-citation-link:focus-visible {
  color: var(--accent);
  text-decoration-color: currentColor;
}

@media (prefers-reduced-motion: reduce) {
  .why-citation-link {
    transition: none;
  }
}

/* ---------- the questions ----------
   Serif questions, plain answers, one hairline between each pair, one column
   at a comfortable measure. No accordion: these five answers are the ones a
   reader came for, and the page's one script belongs to the form. */

.faq {
  padding-top: clamp(48px, 6vw, 96px);
}

.faq-list {
  max-width: 68ch;
  border-bottom: var(--hairline-card);
}

.faq-item {
  border-top: var(--hairline-card);
  padding-block: clamp(22px, 2.4vw, 32px);
}

.faq-q {
  font-family: var(--type-title-family);
  font-weight: var(--type-title-weight);
  font-size: clamp(21px, 1.8vw, 27px);
  line-height: 1.2;
  color: var(--content-primary);
  max-width: 32ch;
  text-wrap: balance;
}

.faq-a {
  margin-top: var(--space-md);
  line-height: 1.6;
  color: var(--content-secondary);
}

.faq-note {
  margin-top: clamp(22px, 2.4vw, 32px);
  max-width: 68ch;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
}

/* ---------- the waitlist ----------
   The page's one full accent-tinted band, and the only place it asks the
   reader for anything. The form is OURS since 2026-09-15: the card below is
   this page's own markup and this page's own <form>, every string in it from
   the site file, and one script of ours (waitlist.js) validating the answers
   and posting them to /api/waitlist on this origin. It replaced the team's
   Mailjet widget in a sandboxed frame, whose document could not carry the
   campaign parameters a signup is attributed by. What stays OUTSIDE the card
   is what stayed outside the frame: where the policy is, and how to reach
   us if the form does not work. */

.waitlist {
  margin-top: clamp(44px, 5.5vw, 84px);
  background: var(--accent-tint);
  padding-block: clamp(48px, 6.5vw, 100px);
  scroll-margin-top: clamp(60px, 8vh, 88px);
}

.waitlist .section-headline {
  color: var(--accent-deep);
  max-width: 22ch;
}

.waitlist .section-headline .line-b {
  color: var(--accent);
}

.waitlist-body {
  margin-top: clamp(18px, 2vw, 26px);
  font-size: clamp(17px, 1.4vw, 20px);
  line-height: 1.55;
  color: var(--accent-deep);
  max-width: 46ch;
}

/* ---------- the form's card ----------
   The page's own card language - surface, hairline, radius, the card's own
   padding - and therefore THEME-AWARE, which the frame's card could not be:
   --embed-ground, a literal #FFFFFF matching a form background set in
   Mailjet's builder, died with the frame, and with it the four blocks of
   measured per-locale frame heights (our own flow layout has no document
   height to measure). No shadow: this band draws cards with a hairline, not
   a lift. position: relative is for the honeypot below, which is taken out
   of the flow and clipped inside the card.

   NAMESPACE NOTE. The waveform band's level classes are .wl-<number>,
   generated at the end of this sheet; the form's are .wl-<word>. The two
   never name the same class, and nothing in this section matches a bar. */
.waitlist-card {
  position: relative;
  max-width: 520px;
  background: var(--surface);
  border: var(--hairline-card);
  border-radius: var(--radius-lg);
  padding: var(--card-pad);
}

.wl-form {
  display: flex;
  flex-direction: column;
  gap: clamp(18px, 2.2vw, 26px);
}

/* Each question is a small stack: its label or legend, the control, its
   own message under it. The fieldset joins the stack as a plain box: a
   browser gives it a border and padding of its own, and min-width: 0 is
   the fix for its intrinsic min-content width, which otherwise refuses to
   shrink inside a narrow card. */
.wl-field,
.wl-choice,
.wl-consent-field,
.wl-check {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.wl-choice {
  border: 0;
  padding: 0;
  min-width: 0;
}

.wl-label,
.wl-legend {
  padding: 0;
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--content-primary);
}

.wl-help {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
  max-width: 52ch;
}

/* 16px is not a taste: below it iOS Safari zooms the whole page on focus,
   and a reader typing an address into a zoomed page loses the button. font:
   inherit first, so the field takes the page's own face, and the size is
   then set on top of it. The ground is the page's paper, one step below the
   card's surface, so the field reads as a well and not as a second card. */
.wl-input {
  width: 100%;
  font: inherit;
  font-size: 16px;
  line-height: 1.4;
  color: var(--content-primary);
  background: var(--background);
  border: var(--hairline-interactive);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  -webkit-appearance: none;
  appearance: none;
}

.wl-input::placeholder {
  color: var(--content-secondary);
  opacity: 1;
}

/* One focus ring for every control in the card: the accent, outside the
   box, the ring links and the button already take. */
.wl-input:focus-visible,
.wl-option input:focus-visible,
.wl-consent input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* The two phones as two pills, both always visible: a radio group with
   nothing checked is honestly empty, where a required <select> needs a
   placeholder option that looks like a valid pre-selection. */
.wl-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm-md);
}

.wl-option {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm-md);
  padding: 10px 16px;
  border: var(--hairline-interactive);
  border-radius: var(--radius-pill);
  font-size: 16px;
  line-height: 1.2;
  color: var(--content-primary);
  cursor: pointer;
}

.wl-option input,
.wl-consent input {
  flex: none;
  margin: 0;
  width: 18px;
  height: 18px;
  accent-color: var(--accent);
}

/* The chosen pill takes the band's own tint pairing (accentTint under
   accentDeep). :has() is progressive: an engine without it keeps the native
   radio's own dot as the whole signal, which is enough. */
.wl-option:has(input:checked) {
  background: var(--accent-tint);
  border-color: var(--accent);
  color: var(--accent-deep);
}

/* The consent sentence beside its box, in caption type: it is the one
   sentence on the page a reader ticks, and its link is the policy's. */
.wl-consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm-md);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
  cursor: pointer;
}

.wl-consent input {
  margin-top: 1px;
}

.wl-consent a {
  color: var(--accent-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The honeypot: a field a person never sees and a naive form-filler fills.
   Clipped to nothing and taken out of the flow, NOT display: none - the
   fillers this catches skip hidden fields by that very property, and the
   clip leaves the field "visible" to them. aria-hidden and tabindex="-1" in
   the markup keep it out of every real reader's path. */
.wl-honey {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Where Turnstile draws its check, once the reader has touched the form.
   The widget's own box is 300 by 65; the slot reserves that height from the
   start, so the card does not jump when the check arrives under a reader's
   hands, and the help line above it says what the empty slot is for. */
.wl-turnstile {
  min-height: 65px;
}

.wl-msg {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  max-width: 52ch;
}

.wl-msg-error {
  color: var(--danger);
}

/* The two messages outside the form (the generic failure, the rate limit)
   sit in a live region under it; a shown one takes its own air above. */
.wl-status .wl-msg {
  margin-top: var(--space-md);
}

.wl-submit {
  align-self: flex-start;
}

/* The busy state: the button goes quiet in the app's own disabled pairing
   while a post is in flight, and the pointer says so. Later in the sheet
   than .cta-button:hover and at the same specificity, so a hover over a
   disabled button no longer paints it as clickable. */
.cta-button:disabled {
  background: var(--disabled-fill);
  color: var(--disabled-content);
  cursor: progress;
}

.waitlist-reassurance {
  margin-top: clamp(18px, 2vw, 26px);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--accent-deep);
}

/* The policy pointer and the fallback: both OUTSIDE the card, on purpose.
   The policy has to be reachable before a reader touches the form and
   whether or not the script ran, and the fallback is what the page offers
   against the case <noscript> cannot see - a script that loaded and then
   failed - so it stands permanently. Neither is an error message and
   neither is styled as one; they take the caption treatment the retired
   "not live" notice used. */
.waitlist-policy,
.waitlist-fallback {
  margin-top: var(--space-md);
  max-width: 60ch;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--accent-deep);
}

.waitlist-policy a {
  color: var(--accent-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ---------- the success panel ----------
   Replaces the form inside the same card once the function has answered,
   and takes focus so a screen reader lands on the outcome. It is the moment
   the referral line belonged to all along ("you are on the list, now tell
   whoever shares the care"): the line stood at the block's foot while the
   success state lived inside a third party's document, and it moved in
   here the day the page could see that moment. The delayed line shows only
   on a 202, when our record is written but the handover to Mailjet is
   still owed, and the confirmation email really may take longer. */
.wl-success {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.wl-success:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 6px;
  border-radius: var(--radius-sm);
}

.wl-success-headline {
  font-family: var(--type-title-family);
  font-weight: var(--type-title-weight);
  font-size: clamp(23px, 1.9vw, 29px);
  line-height: 1.16;
  color: var(--content-primary);
}

.wl-success-body {
  color: var(--content-secondary);
  max-width: 52ch;
}

.wl-success-delayed,
.wl-noscript {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
  max-width: 52ch;
}

.wl-success-referral {
  margin-top: var(--space-sm);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--accent-deep);
}

/* THE [hidden] RULE, and why it has to exist. The browser's own
   [hidden] { display: none } is a UA rule at specificity (0,1,0); any author
   rule of the same specificity that sets display - .wl-form { display: flex }
   above, .wl-success too - beats it, and every "hidden" state renders. The
   script flips nothing but the hidden attribute (plus disabled, aria-busy
   and focus), so this one rule is the script's whole visual vocabulary:
   (0,2,0), AFTER every .wl-* rule, no !important, scoped to the section so
   it can never reach a bar of the waveform band. */
.waitlist [hidden] {
  display: none;
}

/* ---------- this page's own legal texts ----------
   A typographic appendix: smaller type, a 68ch measure, one hairline per
   document, read when it is needed and never competing with the page above
   it. Each heading IS its anchor, so a reader arriving from a footer link
   lands on the words they clicked, clear of the sticky dock. */

.legal {
  padding-top: clamp(48px, 6vw, 96px);
  padding-bottom: clamp(24px, 3vw, 48px);
}

.legal-heading {
  font-family: var(--type-title-family);
  font-weight: var(--type-title-weight);
  font-size: clamp(24px, 2.1vw, 32px);
  line-height: 1.2;
  color: var(--content-primary);
}

.legal-intro {
  margin-top: var(--space-md);
  max-width: 68ch;
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
}

.legal-doc {
  max-width: 68ch;
  border-top: var(--hairline-card);
  padding-top: clamp(18px, 2vw, 26px);
}

.legal-doc + .legal-doc {
  margin-top: clamp(28px, 3.2vw, 44px);
}

.legal-doc-heading {
  font-family: var(--type-title-family);
  font-weight: var(--type-title-weight);
  font-size: clamp(19px, 1.5vw, 23px);
  line-height: 1.25;
  color: var(--content-primary);
  scroll-margin-top: clamp(60px, 8vh, 88px);
}

.legal-block {
  margin-top: clamp(14px, 1.6vw, 20px);
}

.legal-block-heading {
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--content-primary);
}

.legal-body {
  margin-top: var(--space-xs);
  font-size: var(--type-caption-size);
  line-height: 1.6;
  color: var(--content-secondary);
}

.legal-doc > .legal-body {
  margin-top: var(--space-md);
}

/* ---------- footer: grouped links and the language switch ---------- */

/* The footer carried two lines and now carries ten, so they need a measure:
   at 1400px the long ones ran the full page and the block read as a wall. */
.footer-line {
  max-width: 76ch;
}

/* Six links in one flat row left a reader guessing which document covered
   which thing; the group label is the answer. */
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(24px, 4vw, 56px);
}

.footer-link-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.footer-group-label {
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-secondary);
}

.footer-link-list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

/* Labelled in the other locale's own language: a reader who cannot read this
   page cannot read a label about it either. */
.footer-lang {
  margin-top: var(--space-lg);
}

.footer-lang a {
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-height);
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

@media (min-width: 720px) {
  .persona-row {
    gap: 20px;
  }
}

@media (min-width: 1100px) {
  /* The trio becomes a row only here. Three columns were tried from 720px and
     failed the page's harder language: at a tablet's width Portuguese wrapped
     the category eyebrow onto two lines, the status chip onto two lines inside
     its own pill, and the card headlines onto three, so the three cards no
     longer read as one row of three. Below this width they stack, at a card's
     own measure, and each one is whole. */
  .persona-row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 24px;
  }

  /* The words hold one column and the evidence the other, which is the whole
     shape of the argument: the claim on the left, the number on the right. */
  .why-shell {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    align-items: start;
    column-gap: clamp(32px, 4vw, 72px);
  }

  /* The split, at the width where it earns its keep. */
  .faq-shell,
  .waitlist-shell,
  .legal-shell {
    display: grid;
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
    column-gap: clamp(32px, 5vw, 96px);
  }

  .split-body {
    margin-top: 0;
  }

  /* The heading travels with the reading matter it labels. Both of these
     sections are long enough to scroll several screens, and a heading that
     has left the viewport has stopped labelling anything; it also gives the
     left column something to do besides be empty. It clears the sticky dock
     by its own top offset. Not applied to the waitlist: that section is one
     screen tall and its heading never leaves.

     The sticky element is the wrapper INSIDE the head column, never the
     column itself: the column is a stretched grid item, so it is as tall as
     the reading matter beside it, and that height is what the heading
     travels through. Sticky on the grid item was tried and did not move at
     all, because a grid item aligned to the start has only its own height
     to travel in. */
  .faq-shell .split-head-stick,
  .legal-shell .split-head-stick {
    position: sticky;
    top: clamp(76px, 9vh, 104px);
  }

  /* The reading column keeps its own top edge, and the waitlist (one screen
     tall, no travelling heading) keeps both of its own. */
  .faq-shell .split-body,
  .legal-shell .split-body,
  .waitlist-shell .split-head,
  .waitlist-shell .split-body {
    align-self: start;
  }
}

/* ===================================================================== *
 * THE THRESHOLD - two-brand handoff.
 *
 * Two worlds meet on this page. dehaze brings you in (the strip at the
 * top) and signs the back cover (the colophon at the bottom); Scribe
 * carries everything between them. The dehaze layer therefore does NOT
 * take the page's theme: it holds the company's own constants in light
 * and dark alike, exactly the way the device bezels above hold theirs.
 * Every value in --dh-* is a documented company literal lifted from
 * dehaze's own marketing stylesheet, never a Scribe token.
 * ===================================================================== */

:root {
  /* Company literals (dehaze's own header bar, verbatim): the bar's glass
     rgba(247,248,250,.8) over blur(10px), its 16px corner, its three-part
     shadow (two soft drops and a 0.9px hairline ring), the button's
     #1c1e23 ground with white type at 15.5px/520 and a 14px corner, and
     --ring #c1a8ff for focus. The page ground under the bar is the
     company's --background #fcfcfd (252, 252, 253, the value below and the
     literal the bar-glass comment further down cites); the ink is
     --foreground #1c1e23.
     They are theme-CONSTANT here. The reason is the wordmark: the shipped
     dehaze-logo.png is pure black ink (0,0,0) on transparency, and this
     page may not recolour it, so the company's ground has to stay the
     light ground the mark was drawn for. #1c1e23 is dehaze's INK, and it
     is where the near-black lives: in the type and in the button. */
  --dh-ground: 252, 252, 253;
  /* ONE density for the company's ground, at both ends of the page and in
     both themes: the same white, laid at the same weight, taking a hint of
     whatever it is laid on. Over Scribe's warm paper it settles at
     #FCFBFC, a shade cooler than the page's #FAF7F1 - a cool white above a
     warm one, which is the seam in light mode. Over Scribe's near-black it
     settles at #E9E9EA.

     0.92 and not something thinner: the wordmark is pure black ink on
     transparency and may not be recoloured, so the company's ground has to
     stay a real white. Thinner glass (0.66 was tried and rendered) hazes
     down to a #B0B0B1 pewter in dark mode, which reads as a washed-out
     accident rather than as the company's own paper, and takes the mark's
     hairline strokes down with it. A bright band above a dark page is the
     louder answer and the deliberate one: it is dehaze's letterhead, and
     the page crosses out of it. */
  --dh-density: 0.92;
  --dh-ink: #1c1e23;
  /* One line ink, two appearances: the strip's border-bottom and the
     colophon's border-top. */
  --dh-line-ink: 20, 30, 50;
  --dh-line: rgba(var(--dh-line-ink), 0.10);
  --dh-ring: #c1a8ff;
  /* The bar's own glass, and it is NOT the ground it sits on: 247,248,250
     at 0.8 is a shade cooler and a shade darker than the company's
     #fcfcfd letterhead, which is the whole reason a floating bar reads as
     an object on a page rather than as a band. */
  --dh-bar-ground: 247, 248, 250;
  --dh-bar-density: 0.8;
  /* dehaze's own three-part shadow, verbatim. The last layer is a 0.9px
     ring rather than a border, so the corner radius carries it around the
     bar without a second box. */
  --dh-bar-shadow:
    0 0 14.5px -7.3px rgba(42, 51, 70, 0.04),
    0 2.7px 2.7px -1.4px rgba(42, 51, 70, 0.05),
    0 0 0 0.9px rgba(14, 63, 126, 0.06);
  --dh-btn-shadow: 0 4px 4px rgba(0, 0, 0, 0.14);
  /* The company's own stack, headed by the two faces it licenses. No font
     file is added for the company layer, so on a machine without them the
     stack degrades to the system UI face; the two brands still do not
     share the product's serif. */
  --dh-font: "Inter Tight", "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* The bar's own geometry, from dehaze's header: 58px tall, 16px corner,
     20px of padding inside it.

     Its WIDTH is not a company literal but an alignment. The bar is the
     page's own measure plus its own two paddings, and the strip it floats
     on gives back exactly one padding on each side (--dh-strip-pad): the
     wordmark's left edge therefore lands on the Scribe topbar's left edge
     and the button's right edge on its right edge, at every width. The
     glass simply extends one bar-padding further out than the content it
     holds, which is what makes it read as an object laid over the measure
     rather than as a second, narrower column. It was 1100px before: a
     company number with no relationship to this page's 1400px measure,
     visibly not lining up with anything below it.

     Both derived properties are written in terms of --dh-bar-pad, so the
     phone-width block at the end of the stylesheet moves the padding once
     and the alignment holds. --dh-strip-pad stays positive everywhere,
     because the gutter's own 16px floor is above the 14px the bar's padding
     comes down to there. */
  --dh-bar-h: 58px;
  --dh-bar-radius: 16px;
  --dh-bar-pad: 20px;
  --dh-bar-w: calc(var(--page-measure) - 2 * var(--page-gutter)
                   + 2 * var(--dh-bar-pad));
  --dh-strip-pad: calc(var(--page-gutter) - var(--dh-bar-pad));
  /* The breathing room the floating bar needs above and below it, and
     with it the height of the company's zone: gap, bar, gap, hairline.
     That total is also the scroll distance the settle runs over, which is
     why it is a named property and not a padding sum. */
  --dh-bar-gap: 11px;
  --dh-strip-h: calc(var(--dh-bar-h) + var(--dh-bar-gap) * 2 + 1px);

  /* The Scribe dock's chrome, in Scribe's own inks. The ground is the
     paper token at 0.82 with a blur behind it, which is what keeps the
     lockup legible where the accent card or a phone bezel passes under
     the bar. The hairline is heavier than --hairline-card on purpose:
     --hairline-card separates two cards, this separates chrome from the
     page and has to survive being drawn over a photograph. */
  --dock-ground: rgba(250, 247, 241, 0.86);
  --dock-line: rgba(36, 39, 43, 0.14);
  /* One blur for the dock, wide enough that a phone bezel or a line of
     tile copy passing under the bar reads as a shadow in the material and
     not as text you can still almost read. */
  --dock-blur: blur(30px) saturate(1.8);
}

@media (prefers-color-scheme: dark) {
  :root {
    --dock-ground: rgba(22, 24, 26, 0.84);
    --dock-line: rgba(238, 240, 238, 0.16);
  }
}

/* ---------- the dehaze bar ----------
   dehaze's own header, as dehaze draws it: a floating rounded glass bar,
   not a band. .dh-strip is the company's ZONE - the full-bleed letterhead
   the bar floats on, whose bottom edge is the SEAM the product's dock
   takes over from. .dh-bar is the object itself. */

.dh-strip {
  padding: var(--dh-bar-gap) var(--dh-strip-pad);
  background: rgba(var(--dh-ground), var(--dh-density));
  /* The threshold line. It is drawn in the COMPANY's ink and it does not
     change with the page's theme, because the boundary belongs to the
     side that is handing over. */
  border-bottom: 1px solid var(--dh-line);
}

.dh-bar {
  max-width: var(--dh-bar-w);
  height: var(--dh-bar-h);
  margin-inline: auto;
  padding-inline: var(--dh-bar-pad);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  background: rgba(var(--dh-bar-ground), var(--dh-bar-density));
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: var(--dh-bar-radius);
  box-shadow: var(--dh-bar-shadow);
}

/* The authentic wordmark, unmodified: no filter, no opacity, no tint. Its
   height is the only thing this stylesheet sets; the width follows the
   453x144 artwork. */
.dh-wordmark {
  height: 22px;
  width: auto;
}

/* dehaze's .btn, scaled to stand inside a 58px bar: their standalone
   14px/24px padding would leave 2px of glass above and below it, so the
   block half comes down to 10px and the inline half to 20px. Everything
   else is theirs untouched - the near-black ground, white type, 14px
   corner, and the soft drop under it. 520 is a variable-font weight the
   company sets; 500 is the same declaration for a browser that will not
   parse it, and it is why the property is written twice. */
.dh-cta {
  font-family: var(--dh-font);
  font-size: 15.5px;
  font-weight: 500;
  font-weight: 520;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: #ffffff;
  background: var(--dh-ink);
  border-radius: 14px;
  padding: 10px 20px;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: var(--dh-btn-shadow);
}

/* The company's own --ring lavender, on the company's own control. It is
   the only trace of dehaze's purple family left on the page, and it is
   only ever drawn for a keyboard. */
.dh-cta:focus-visible {
  outline: 3px solid var(--dh-ring);
  outline-offset: 2px;
}

/* ---------- the Scribe dock ----------
   The product's topbar, one step below the threshold. It is page content
   at rest and chrome once the strip has left; the dock is the full-bleed
   layer that carries the chrome, so .topbar keeps its own measure and
   gutters untouched. */

.topbar-dock {
  position: sticky;
  top: 0;
  z-index: 30;
}

.topbar-dock::before,
.topbar-dock::after {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
}

.topbar-dock::before {
  inset: 0;
  background: var(--dock-ground);
  -webkit-backdrop-filter: var(--dock-blur);
  backdrop-filter: var(--dock-blur);
}

.topbar-dock::after {
  inset: auto 0 0 0;
  height: 1px;
  background: var(--dock-line);
}

/* Chrome proportions: the shipped 24/8 padding was a page-header rhythm,
   which reads lopsided once the bar is pinned. Even padding turns it into
   a bar. */
.topbar {
  padding-top: 13px;
  padding-bottom: 13px;
}

/* ---------- variant B: the settle ----------
   As the company's zone scrolls out, the dock's ground eases in behind
   the lockup and the hairline draws last, so the bar arrives at its stuck
   state at the same instant the company's line leaves the viewport: one
   rule is handed to the other. The whole move is two opacities over the
   zone's own 81px (11 + 58 + 11 + the hairline) and it is over before the
   hero headline reaches the top.

   Everything the settle needs is inside this @supports block, so a
   browser without scroll-driven animations, or a reader who asked for
   less motion, gets variant A: the same chrome, already on. */

@keyframes dock-ground-settle {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes dock-line-settle {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .topbar-dock::before {
      opacity: 0;
      animation: dock-ground-settle auto linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 var(--dh-strip-h);
    }

    .topbar-dock::after {
      opacity: 0;
      animation: dock-line-settle auto linear both;
      animation-timeline: scroll(root block);
      /* Starts once the company's bar has cleared: the floating object
         leaves at 69px of the zone's 81px, and the product's hairline is
         the last thing to arrive, over the 12px that remain. */
      animation-range: calc(var(--dh-strip-h) - 12px) var(--dh-strip-h);
    }
  }
}

/* ---------- the dehaze colophon ----------
   The back cover, and the bar's twin: the same company letterhead, and on
   it the same floating object - one measure, one corner, one glass, one
   shadow. The company opens and closes the page with the same shape and
   neither end takes the theme of what is between them. A signature rather
   than a slab: it holds one line, so it is shorter than the bar it
   answers. */

.dh-colophon {
  padding: var(--dh-bar-gap) var(--dh-strip-pad) 22px;
  background: rgba(var(--dh-ground), var(--dh-density));
  border-top: 1px solid var(--dh-line);
}

/* No backdrop-filter here, unlike the bar: this glass is laid on the
   company's own opaque letterhead with the page already ended above it,
   so there is nothing behind it left to blur. */
.dh-colophon-inner {
  max-width: var(--dh-bar-w);
  margin-inline: auto;
  padding: 14px var(--dh-bar-pad);
  background: rgba(var(--dh-bar-ground), var(--dh-bar-density));
  border-radius: var(--dh-bar-radius);
  box-shadow: var(--dh-bar-shadow);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: 14px;
  row-gap: 10px;
}

.dh-colophon .dh-wordmark {
  height: 19px;
}

/* Set in the company's full ink, not in its muted grey. This one line is
   where dehaze's near-black #1c1e23 lives on the page: the brief asked for
   the colophon to carry it, and since the wordmark is black ink that has
   to sit on a light ground, the near-black belongs in the type. A
   signature is not a footnote, and dehaze's own #63666b would have landed
   at 4.28:1 on this ground anyway, just under AA at this size. The line
   itself comes up to 14px with the bar's own -0.01em: it is set in the
   company's type now, not in a footnote's. */
.dh-colophon-line {
  font-family: var(--dh-font);
  font-size: 14px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--dh-ink);
}

/* ---------- a hand's width ---------- */

/* The bar keeps its 58px at every width, and with it one scroll distance
   for the settle everywhere. Its 3px focus ring has 9px of glass to clear
   above and below the button, and the zone's 11px gap outside that, so
   the ring is never cut by an edge. What shrinks on a phone is the
   content inside the bar, not the bar. */
@media (max-width: 719px) {
  /* One move, and the bar, the colophon and the strip's give-back all
     follow it: --dh-bar-w and --dh-strip-pad are both written in terms of
     this, so the wordmark stays on the topbar's own left edge here too. */
  :root {
    --dh-bar-pad: 14px;
  }

  .dh-wordmark {
    height: 18px;
  }

  /* The button comes down with the bar's contents, and it has to: the
     longest label the page ships is pt-BR's "Entrar na lista de espera",
     and at the desktop size it leaves the wordmark 4px of air at 360px.
     At 13.5px there is room for both to be read as two things. */
  .dh-cta {
    font-size: 13.5px;
    padding: 8px 14px;
  }

  .topbar {
    padding-top: 11px;
    padding-bottom: 11px;
  }
}

/* ---------- kit additions: per-shot and per-mode refinements ----------
   Rules for presenter modes and measured crop presets that only SOME site
   files use. They live in the one kit sheet on purpose: an arrangement is
   the site file's decision, but what a treatment looks like is the kit's,
   and a mode class either matches or it does not. */

/* The record-hero crop preset, at EVERY width: for a crop-phone tile drawing
   the HOME screen, which the shared cuts were never measured against. Both
   of them, 375/400 at tablet and up and 375/330 at a hand's width, slice
   straight through the record button's disc, and a tile that says "press
   record" showing half a button reads as a rendering fault. 375/580 is
   source row 1392 of the 900px capture, a hand's breadth past the whole
   record group: the button (its halo ends at row 1180), "Record a visit"
   (1236-1264) and "Make sure you've asked your doctor for consent"
   (1292-1320). Flat paper in the light ink and flat ground in the dark one,
   measured on both files, spread 0. So the button AND the consent reminder
   stay inside the card - on a page whose band mode dropped the consent ask,
   this screenshot is where the page still shows the app asking. */
.device-crop.crop-record-hero img {
  aspect-ratio: 375 / 580;
}

/* A band in "heading" mode IS the feature section's heading, so its type
   sits at the section scale the personas, the faq and the waitlist use, not
   at the band's display size. That size was for one line ("Every visit
   begins as sound."); a heading PAIR is two sentences, and at 76px in this
   column it broke into five lines and shouted down the memory statistic it
   follows. Same family, same tracking, same balance - one step quieter. */
.band-wave--heading .band-headline {
  font-size: clamp(30px, 3.9vw, 54px);
  line-height: 1.08;
  max-width: 24ch;
}

/* The demo-content disclosure in "grid" placement: one quiet caption line
   closing the grid from below, where the screenshots it labels are. */
.grid-demo-note {
  max-width: var(--page-measure);
  margin: clamp(18px, 2vw, 28px) auto 0;
  padding-inline: var(--page-gutter);
  font-size: var(--type-caption-size);
  line-height: var(--type-caption-height);
  color: var(--content-recessive);
}

/* The legal page's dock lockup is the way back to the landing page. A
   wordmark with a rule under it would read as a broken brand, so the
   affordance is the pointer and the focus ring the base reset already
   draws for every link. */
.lockup-link {
  color: inherit;
  text-decoration: none;
}

/* The bento's grid maps, GENERATED from the site file's layout data. The
   phone reads the tiles in DOM order; these maps deal the SAME tiles out at
   width, row by row in that order, so the phone's linear reading and the
   desktop's rows tell one story, never two. Edit the site file, not this. */
@media (min-width: 720px) {
  .bento {
    grid-template-areas:
      "recording recording recording guidance guidance guidance"
      "summary summary key-facts key-facts key-facts key-facts"
      "qa qa qa qa transcript transcript"
      "share share share visits-timeline visits-timeline visits-timeline";
  }

  .area-guidance { grid-area: guidance; }
  .area-key-facts { grid-area: key-facts; }
  .area-qa { grid-area: qa; }
  .area-recording { grid-area: recording; }
  .area-share { grid-area: share; }
  .area-summary { grid-area: summary; }
  .area-transcript { grid-area: transcript; }
  .area-visits-timeline { grid-area: visits-timeline; }
}

@media (min-width: 1100px) {
  .bento {
    grid-template-areas:
      "recording recording guidance guidance summary summary"
      "key-facts key-facts key-facts key-facts qa qa"
      "transcript transcript share share visits-timeline visits-timeline";
  }
}

/* The waveform band's count and cadence, from the generator so
   the stylesheet and the markup cannot disagree: frames in the
   recording (one bar each, from demo-levels.json) and the
   recorder's own sample interval (WAVE_FRAME_MS), which is both
   the step between two bars' phases and, times the frame count,
   one pass over the whole recording. */
:root {
  --wave-bars: 160;
  --wave-frame: 50ms;
}

/* The band's bars at rest, one rule per distinct level. The bar is
   laid out at the meter's full height and SCALED from its bottom
   edge, the way LevelMeter draws a bar up from the baseline; the
   scale is the level, floored at the painter's resting nub (2 *
   radius of the 52px meter), and the opacity is its 0.4 -> 1.0 ramp.
   GENERATED from demo-levels.json - see generate.py. */
.wl-15 { transform: scaleY(0.15); opacity: 0.49; }
.wl-18 { transform: scaleY(0.18); opacity: 0.508; }
.wl-19 { transform: scaleY(0.19); opacity: 0.514; }
.wl-23 { transform: scaleY(0.23); opacity: 0.538; }
.wl-25 { transform: scaleY(0.25); opacity: 0.55; }
.wl-30 { transform: scaleY(0.3); opacity: 0.58; }
.wl-32 { transform: scaleY(0.32); opacity: 0.592; }
.wl-34 { transform: scaleY(0.34); opacity: 0.604; }
.wl-38 { transform: scaleY(0.38); opacity: 0.628; }
.wl-41 { transform: scaleY(0.41); opacity: 0.646; }
.wl-42 { transform: scaleY(0.42); opacity: 0.652; }
.wl-45 { transform: scaleY(0.45); opacity: 0.67; }
.wl-47 { transform: scaleY(0.47); opacity: 0.682; }
.wl-48 { transform: scaleY(0.48); opacity: 0.688; }
.wl-50 { transform: scaleY(0.5); opacity: 0.7; }
.wl-51 { transform: scaleY(0.51); opacity: 0.706; }
.wl-52 { transform: scaleY(0.52); opacity: 0.712; }
.wl-53 { transform: scaleY(0.53); opacity: 0.718; }
.wl-54 { transform: scaleY(0.54); opacity: 0.724; }
.wl-55 { transform: scaleY(0.55); opacity: 0.73; }
.wl-56 { transform: scaleY(0.56); opacity: 0.736; }
.wl-58 { transform: scaleY(0.58); opacity: 0.748; }
.wl-60 { transform: scaleY(0.6); opacity: 0.76; }
.wl-61 { transform: scaleY(0.61); opacity: 0.766; }
.wl-62 { transform: scaleY(0.62); opacity: 0.772; }
.wl-63 { transform: scaleY(0.63); opacity: 0.778; }
.wl-64 { transform: scaleY(0.64); opacity: 0.784; }
.wl-65 { transform: scaleY(0.65); opacity: 0.79; }
.wl-66 { transform: scaleY(0.66); opacity: 0.796; }
.wl-67 { transform: scaleY(0.67); opacity: 0.802; }
.wl-68 { transform: scaleY(0.68); opacity: 0.808; }
.wl-69 { transform: scaleY(0.69); opacity: 0.814; }
.wl-70 { transform: scaleY(0.7); opacity: 0.82; }
.wl-71 { transform: scaleY(0.71); opacity: 0.826; }
.wl-72 { transform: scaleY(0.72); opacity: 0.832; }
.wl-73 { transform: scaleY(0.73); opacity: 0.838; }
.wl-74 { transform: scaleY(0.74); opacity: 0.844; }
.wl-75 { transform: scaleY(0.75); opacity: 0.85; }
.wl-76 { transform: scaleY(0.76); opacity: 0.856; }
.wl-77 { transform: scaleY(0.77); opacity: 0.862; }
.wl-78 { transform: scaleY(0.78); opacity: 0.868; }
.wl-79 { transform: scaleY(0.79); opacity: 0.874; }
.wl-80 { transform: scaleY(0.8); opacity: 0.88; }
.wl-81 { transform: scaleY(0.81); opacity: 0.886; }

/* THE BOUNCE. One keyframes block for the whole band: the entire
   recording, one keyframe per 50 ms sample, scaling each bar from the
   baseline and shading it on the painter's ramp. Every bar runs THIS
   animation, so a browser holds one block however many bars are on
   the page. Between two samples the bars interpolate rather than
   hold - see WAVE_TIMING in generate.py for the two filmstrips that
   settled it. GENERATED from demo-levels.json - see generate.py. */
@keyframes wave-level {
  0% { transform: scaleY(0.45); opacity: 0.67; }
  0.625% { transform: scaleY(0.66); opacity: 0.796; }
  1.25% { transform: scaleY(0.73); opacity: 0.838; }
  1.875% { transform: scaleY(0.71); opacity: 0.826; }
  2.5% { transform: scaleY(0.66); opacity: 0.796; }
  3.125% { transform: scaleY(0.6); opacity: 0.76; }
  3.75% { transform: scaleY(0.62); opacity: 0.772; }
  4.375% { transform: scaleY(0.72); opacity: 0.832; }
  5% { transform: scaleY(0.75); opacity: 0.85; }
  5.625% { transform: scaleY(0.76); opacity: 0.856; }
  6.25% { transform: scaleY(0.77); opacity: 0.862; }
  6.875% { transform: scaleY(0.77); opacity: 0.862; }
  7.5% { transform: scaleY(0.74); opacity: 0.844; }
  8.125% { transform: scaleY(0.76); opacity: 0.856; }
  8.75% { transform: scaleY(0.77); opacity: 0.862; }
  9.375% { transform: scaleY(0.78); opacity: 0.868; }
  10% { transform: scaleY(0.78); opacity: 0.868; }
  10.625% { transform: scaleY(0.78); opacity: 0.868; }
  11.25% { transform: scaleY(0.77); opacity: 0.862; }
  11.875% { transform: scaleY(0.78); opacity: 0.868; }
  12.5% { transform: scaleY(0.77); opacity: 0.862; }
  13.125% { transform: scaleY(0.72); opacity: 0.832; }
  13.75% { transform: scaleY(0.74); opacity: 0.844; }
  14.375% { transform: scaleY(0.75); opacity: 0.85; }
  15% { transform: scaleY(0.75); opacity: 0.85; }
  15.625% { transform: scaleY(0.75); opacity: 0.85; }
  16.25% { transform: scaleY(0.73); opacity: 0.838; }
  16.875% { transform: scaleY(0.69); opacity: 0.814; }
  17.5% { transform: scaleY(0.56); opacity: 0.736; }
  18.125% { transform: scaleY(0.5); opacity: 0.7; }
  18.75% { transform: scaleY(0.47); opacity: 0.682; }
  19.375% { transform: scaleY(0.41); opacity: 0.646; }
  20% { transform: scaleY(0.32); opacity: 0.592; }
  20.625% { transform: scaleY(0.25); opacity: 0.55; }
  21.25% { transform: scaleY(0.19); opacity: 0.514; }
  21.875% { transform: scaleY(0.15); opacity: 0.49; }
  22.5% { transform: scaleY(0.51); opacity: 0.706; }
  23.125% { transform: scaleY(0.68); opacity: 0.808; }
  23.75% { transform: scaleY(0.73); opacity: 0.838; }
  24.375% { transform: scaleY(0.76); opacity: 0.856; }
  25% { transform: scaleY(0.76); opacity: 0.856; }
  25.625% { transform: scaleY(0.77); opacity: 0.862; }
  26.25% { transform: scaleY(0.77); opacity: 0.862; }
  26.875% { transform: scaleY(0.78); opacity: 0.868; }
  27.5% { transform: scaleY(0.79); opacity: 0.874; }
  28.125% { transform: scaleY(0.79); opacity: 0.874; }
  28.75% { transform: scaleY(0.79); opacity: 0.874; }
  29.375% { transform: scaleY(0.78); opacity: 0.868; }
  30% { transform: scaleY(0.76); opacity: 0.856; }
  30.625% { transform: scaleY(0.77); opacity: 0.862; }
  31.25% { transform: scaleY(0.77); opacity: 0.862; }
  31.875% { transform: scaleY(0.74); opacity: 0.844; }
  32.5% { transform: scaleY(0.73); opacity: 0.838; }
  33.125% { transform: scaleY(0.76); opacity: 0.856; }
  33.75% { transform: scaleY(0.76); opacity: 0.856; }
  34.375% { transform: scaleY(0.77); opacity: 0.862; }
  35% { transform: scaleY(0.78); opacity: 0.868; }
  35.625% { transform: scaleY(0.76); opacity: 0.856; }
  36.25% { transform: scaleY(0.69); opacity: 0.814; }
  36.875% { transform: scaleY(0.74); opacity: 0.844; }
  37.5% { transform: scaleY(0.77); opacity: 0.862; }
  38.125% { transform: scaleY(0.76); opacity: 0.856; }
  38.75% { transform: scaleY(0.75); opacity: 0.85; }
  39.375% { transform: scaleY(0.75); opacity: 0.85; }
  40% { transform: scaleY(0.74); opacity: 0.844; }
  40.625% { transform: scaleY(0.73); opacity: 0.838; }
  41.25% { transform: scaleY(0.69); opacity: 0.814; }
  41.875% { transform: scaleY(0.53); opacity: 0.718; }
  42.5% { transform: scaleY(0.42); opacity: 0.652; }
  43.125% { transform: scaleY(0.32); opacity: 0.592; }
  43.75% { transform: scaleY(0.25); opacity: 0.55; }
  44.375% { transform: scaleY(0.34); opacity: 0.604; }
  45% { transform: scaleY(0.51); opacity: 0.706; }
  45.625% { transform: scaleY(0.7); opacity: 0.82; }
  46.25% { transform: scaleY(0.76); opacity: 0.856; }
  46.875% { transform: scaleY(0.7); opacity: 0.82; }
  47.5% { transform: scaleY(0.61); opacity: 0.766; }
  48.125% { transform: scaleY(0.6); opacity: 0.76; }
  48.75% { transform: scaleY(0.71); opacity: 0.826; }
  49.375% { transform: scaleY(0.75); opacity: 0.85; }
  50% { transform: scaleY(0.73); opacity: 0.838; }
  50.625% { transform: scaleY(0.68); opacity: 0.808; }
  51.25% { transform: scaleY(0.74); opacity: 0.844; }
  51.875% { transform: scaleY(0.78); opacity: 0.868; }
  52.5% { transform: scaleY(0.79); opacity: 0.874; }
  53.125% { transform: scaleY(0.79); opacity: 0.874; }
  53.75% { transform: scaleY(0.76); opacity: 0.856; }
  54.375% { transform: scaleY(0.69); opacity: 0.814; }
  55% { transform: scaleY(0.72); opacity: 0.832; }
  55.625% { transform: scaleY(0.75); opacity: 0.85; }
  56.25% { transform: scaleY(0.74); opacity: 0.844; }
  56.875% { transform: scaleY(0.65); opacity: 0.79; }
  57.5% { transform: scaleY(0.72); opacity: 0.832; }
  58.125% { transform: scaleY(0.75); opacity: 0.85; }
  58.75% { transform: scaleY(0.79); opacity: 0.874; }
  59.375% { transform: scaleY(0.78); opacity: 0.868; }
  60% { transform: scaleY(0.78); opacity: 0.868; }
  60.625% { transform: scaleY(0.76); opacity: 0.856; }
  61.25% { transform: scaleY(0.71); opacity: 0.826; }
  61.875% { transform: scaleY(0.74); opacity: 0.844; }
  62.5% { transform: scaleY(0.74); opacity: 0.844; }
  63.125% { transform: scaleY(0.68); opacity: 0.808; }
  63.75% { transform: scaleY(0.55); opacity: 0.73; }
  64.375% { transform: scaleY(0.65); opacity: 0.79; }
  65% { transform: scaleY(0.73); opacity: 0.838; }
  65.625% { transform: scaleY(0.75); opacity: 0.85; }
  66.25% { transform: scaleY(0.74); opacity: 0.844; }
  66.875% { transform: scaleY(0.64); opacity: 0.784; }
  67.5% { transform: scaleY(0.54); opacity: 0.724; }
  68.125% { transform: scaleY(0.52); opacity: 0.712; }
  68.75% { transform: scaleY(0.66); opacity: 0.796; }
  69.375% { transform: scaleY(0.69); opacity: 0.814; }
  70% { transform: scaleY(0.67); opacity: 0.802; }
  70.625% { transform: scaleY(0.62); opacity: 0.772; }
  71.25% { transform: scaleY(0.56); opacity: 0.736; }
  71.875% { transform: scaleY(0.48); opacity: 0.688; }
  72.5% { transform: scaleY(0.38); opacity: 0.628; }
  73.125% { transform: scaleY(0.3); opacity: 0.58; }
  73.75% { transform: scaleY(0.23); opacity: 0.538; }
  74.375% { transform: scaleY(0.18); opacity: 0.508; }
  75% { transform: scaleY(0.52); opacity: 0.712; }
  75.625% { transform: scaleY(0.68); opacity: 0.808; }
  76.25% { transform: scaleY(0.75); opacity: 0.85; }
  76.875% { transform: scaleY(0.77); opacity: 0.862; }
  77.5% { transform: scaleY(0.79); opacity: 0.874; }
  78.125% { transform: scaleY(0.78); opacity: 0.868; }
  78.75% { transform: scaleY(0.78); opacity: 0.868; }
  79.375% { transform: scaleY(0.78); opacity: 0.868; }
  80% { transform: scaleY(0.73); opacity: 0.838; }
  80.625% { transform: scaleY(0.71); opacity: 0.826; }
  81.25% { transform: scaleY(0.71); opacity: 0.826; }
  81.875% { transform: scaleY(0.75); opacity: 0.85; }
  82.5% { transform: scaleY(0.75); opacity: 0.85; }
  83.125% { transform: scaleY(0.69); opacity: 0.814; }
  83.75% { transform: scaleY(0.71); opacity: 0.826; }
  84.375% { transform: scaleY(0.71); opacity: 0.826; }
  85% { transform: scaleY(0.72); opacity: 0.832; }
  85.625% { transform: scaleY(0.75); opacity: 0.85; }
  86.25% { transform: scaleY(0.77); opacity: 0.862; }
  86.875% { transform: scaleY(0.78); opacity: 0.868; }
  87.5% { transform: scaleY(0.78); opacity: 0.868; }
  88.125% { transform: scaleY(0.79); opacity: 0.874; }
  88.75% { transform: scaleY(0.75); opacity: 0.85; }
  89.375% { transform: scaleY(0.68); opacity: 0.808; }
  90% { transform: scaleY(0.73); opacity: 0.838; }
  90.625% { transform: scaleY(0.77); opacity: 0.862; }
  91.25% { transform: scaleY(0.79); opacity: 0.874; }
  91.875% { transform: scaleY(0.8); opacity: 0.88; }
  92.5% { transform: scaleY(0.81); opacity: 0.886; }
  93.125% { transform: scaleY(0.8); opacity: 0.88; }
  93.75% { transform: scaleY(0.79); opacity: 0.874; }
  94.375% { transform: scaleY(0.78); opacity: 0.868; }
  95% { transform: scaleY(0.77); opacity: 0.862; }
  95.625% { transform: scaleY(0.76); opacity: 0.856; }
  96.25% { transform: scaleY(0.72); opacity: 0.832; }
  96.875% { transform: scaleY(0.63); opacity: 0.778; }
  97.5% { transform: scaleY(0.58); opacity: 0.748; }
  98.125% { transform: scaleY(0.52); opacity: 0.712; }
  98.75% { transform: scaleY(0.48); opacity: 0.688; }
  99.375% { transform: scaleY(0.42); opacity: 0.652; }
  100% { transform: scaleY(0.45); opacity: 0.67; }
}

@media (prefers-reduced-motion: no-preference) {
  .wave-row span {
    animation: wave-level var(--wave-cycle) linear infinite;
  }
}

/* THE PHASES: bar i is i frames ahead, so the values travel the row
   right to left, one bar per tick, exactly as samples leave the
   recorder's own window. This is the whole horizontal motion; there
   is no translation anywhere in the band. */
@media (prefers-reduced-motion: no-preference) {
  .wave-row span:nth-child(1) { animation-delay: calc(0 * var(--wave-frame)); }
  .wave-row span:nth-child(2) { animation-delay: calc(-1 * var(--wave-frame)); }
  .wave-row span:nth-child(3) { animation-delay: calc(-2 * var(--wave-frame)); }
  .wave-row span:nth-child(4) { animation-delay: calc(-3 * var(--wave-frame)); }
  .wave-row span:nth-child(5) { animation-delay: calc(-4 * var(--wave-frame)); }
  .wave-row span:nth-child(6) { animation-delay: calc(-5 * var(--wave-frame)); }
  .wave-row span:nth-child(7) { animation-delay: calc(-6 * var(--wave-frame)); }
  .wave-row span:nth-child(8) { animation-delay: calc(-7 * var(--wave-frame)); }
  .wave-row span:nth-child(9) { animation-delay: calc(-8 * var(--wave-frame)); }
  .wave-row span:nth-child(10) { animation-delay: calc(-9 * var(--wave-frame)); }
  .wave-row span:nth-child(11) { animation-delay: calc(-10 * var(--wave-frame)); }
  .wave-row span:nth-child(12) { animation-delay: calc(-11 * var(--wave-frame)); }
  .wave-row span:nth-child(13) { animation-delay: calc(-12 * var(--wave-frame)); }
  .wave-row span:nth-child(14) { animation-delay: calc(-13 * var(--wave-frame)); }
  .wave-row span:nth-child(15) { animation-delay: calc(-14 * var(--wave-frame)); }
  .wave-row span:nth-child(16) { animation-delay: calc(-15 * var(--wave-frame)); }
  .wave-row span:nth-child(17) { animation-delay: calc(-16 * var(--wave-frame)); }
  .wave-row span:nth-child(18) { animation-delay: calc(-17 * var(--wave-frame)); }
  .wave-row span:nth-child(19) { animation-delay: calc(-18 * var(--wave-frame)); }
  .wave-row span:nth-child(20) { animation-delay: calc(-19 * var(--wave-frame)); }
  .wave-row span:nth-child(21) { animation-delay: calc(-20 * var(--wave-frame)); }
  .wave-row span:nth-child(22) { animation-delay: calc(-21 * var(--wave-frame)); }
  .wave-row span:nth-child(23) { animation-delay: calc(-22 * var(--wave-frame)); }
  .wave-row span:nth-child(24) { animation-delay: calc(-23 * var(--wave-frame)); }
  .wave-row span:nth-child(25) { animation-delay: calc(-24 * var(--wave-frame)); }
  .wave-row span:nth-child(26) { animation-delay: calc(-25 * var(--wave-frame)); }
  .wave-row span:nth-child(27) { animation-delay: calc(-26 * var(--wave-frame)); }
  .wave-row span:nth-child(28) { animation-delay: calc(-27 * var(--wave-frame)); }
  .wave-row span:nth-child(29) { animation-delay: calc(-28 * var(--wave-frame)); }
  .wave-row span:nth-child(30) { animation-delay: calc(-29 * var(--wave-frame)); }
  .wave-row span:nth-child(31) { animation-delay: calc(-30 * var(--wave-frame)); }
  .wave-row span:nth-child(32) { animation-delay: calc(-31 * var(--wave-frame)); }
  .wave-row span:nth-child(33) { animation-delay: calc(-32 * var(--wave-frame)); }
  .wave-row span:nth-child(34) { animation-delay: calc(-33 * var(--wave-frame)); }
  .wave-row span:nth-child(35) { animation-delay: calc(-34 * var(--wave-frame)); }
  .wave-row span:nth-child(36) { animation-delay: calc(-35 * var(--wave-frame)); }
  .wave-row span:nth-child(37) { animation-delay: calc(-36 * var(--wave-frame)); }
  .wave-row span:nth-child(38) { animation-delay: calc(-37 * var(--wave-frame)); }
  .wave-row span:nth-child(39) { animation-delay: calc(-38 * var(--wave-frame)); }
  .wave-row span:nth-child(40) { animation-delay: calc(-39 * var(--wave-frame)); }
  .wave-row span:nth-child(41) { animation-delay: calc(-40 * var(--wave-frame)); }
  .wave-row span:nth-child(42) { animation-delay: calc(-41 * var(--wave-frame)); }
  .wave-row span:nth-child(43) { animation-delay: calc(-42 * var(--wave-frame)); }
  .wave-row span:nth-child(44) { animation-delay: calc(-43 * var(--wave-frame)); }
  .wave-row span:nth-child(45) { animation-delay: calc(-44 * var(--wave-frame)); }
  .wave-row span:nth-child(46) { animation-delay: calc(-45 * var(--wave-frame)); }
  .wave-row span:nth-child(47) { animation-delay: calc(-46 * var(--wave-frame)); }
  .wave-row span:nth-child(48) { animation-delay: calc(-47 * var(--wave-frame)); }
  .wave-row span:nth-child(49) { animation-delay: calc(-48 * var(--wave-frame)); }
  .wave-row span:nth-child(50) { animation-delay: calc(-49 * var(--wave-frame)); }
  .wave-row span:nth-child(51) { animation-delay: calc(-50 * var(--wave-frame)); }
  .wave-row span:nth-child(52) { animation-delay: calc(-51 * var(--wave-frame)); }
  .wave-row span:nth-child(53) { animation-delay: calc(-52 * var(--wave-frame)); }
  .wave-row span:nth-child(54) { animation-delay: calc(-53 * var(--wave-frame)); }
  .wave-row span:nth-child(55) { animation-delay: calc(-54 * var(--wave-frame)); }
  .wave-row span:nth-child(56) { animation-delay: calc(-55 * var(--wave-frame)); }
  .wave-row span:nth-child(57) { animation-delay: calc(-56 * var(--wave-frame)); }
  .wave-row span:nth-child(58) { animation-delay: calc(-57 * var(--wave-frame)); }
  .wave-row span:nth-child(59) { animation-delay: calc(-58 * var(--wave-frame)); }
  .wave-row span:nth-child(60) { animation-delay: calc(-59 * var(--wave-frame)); }
  .wave-row span:nth-child(61) { animation-delay: calc(-60 * var(--wave-frame)); }
  .wave-row span:nth-child(62) { animation-delay: calc(-61 * var(--wave-frame)); }
  .wave-row span:nth-child(63) { animation-delay: calc(-62 * var(--wave-frame)); }
  .wave-row span:nth-child(64) { animation-delay: calc(-63 * var(--wave-frame)); }
  .wave-row span:nth-child(65) { animation-delay: calc(-64 * var(--wave-frame)); }
  .wave-row span:nth-child(66) { animation-delay: calc(-65 * var(--wave-frame)); }
  .wave-row span:nth-child(67) { animation-delay: calc(-66 * var(--wave-frame)); }
  .wave-row span:nth-child(68) { animation-delay: calc(-67 * var(--wave-frame)); }
  .wave-row span:nth-child(69) { animation-delay: calc(-68 * var(--wave-frame)); }
  .wave-row span:nth-child(70) { animation-delay: calc(-69 * var(--wave-frame)); }
  .wave-row span:nth-child(71) { animation-delay: calc(-70 * var(--wave-frame)); }
  .wave-row span:nth-child(72) { animation-delay: calc(-71 * var(--wave-frame)); }
  .wave-row span:nth-child(73) { animation-delay: calc(-72 * var(--wave-frame)); }
  .wave-row span:nth-child(74) { animation-delay: calc(-73 * var(--wave-frame)); }
  .wave-row span:nth-child(75) { animation-delay: calc(-74 * var(--wave-frame)); }
  .wave-row span:nth-child(76) { animation-delay: calc(-75 * var(--wave-frame)); }
  .wave-row span:nth-child(77) { animation-delay: calc(-76 * var(--wave-frame)); }
  .wave-row span:nth-child(78) { animation-delay: calc(-77 * var(--wave-frame)); }
  .wave-row span:nth-child(79) { animation-delay: calc(-78 * var(--wave-frame)); }
  .wave-row span:nth-child(80) { animation-delay: calc(-79 * var(--wave-frame)); }
  .wave-row span:nth-child(81) { animation-delay: calc(-80 * var(--wave-frame)); }
  .wave-row span:nth-child(82) { animation-delay: calc(-81 * var(--wave-frame)); }
  .wave-row span:nth-child(83) { animation-delay: calc(-82 * var(--wave-frame)); }
  .wave-row span:nth-child(84) { animation-delay: calc(-83 * var(--wave-frame)); }
  .wave-row span:nth-child(85) { animation-delay: calc(-84 * var(--wave-frame)); }
  .wave-row span:nth-child(86) { animation-delay: calc(-85 * var(--wave-frame)); }
  .wave-row span:nth-child(87) { animation-delay: calc(-86 * var(--wave-frame)); }
  .wave-row span:nth-child(88) { animation-delay: calc(-87 * var(--wave-frame)); }
  .wave-row span:nth-child(89) { animation-delay: calc(-88 * var(--wave-frame)); }
  .wave-row span:nth-child(90) { animation-delay: calc(-89 * var(--wave-frame)); }
  .wave-row span:nth-child(91) { animation-delay: calc(-90 * var(--wave-frame)); }
  .wave-row span:nth-child(92) { animation-delay: calc(-91 * var(--wave-frame)); }
  .wave-row span:nth-child(93) { animation-delay: calc(-92 * var(--wave-frame)); }
  .wave-row span:nth-child(94) { animation-delay: calc(-93 * var(--wave-frame)); }
  .wave-row span:nth-child(95) { animation-delay: calc(-94 * var(--wave-frame)); }
  .wave-row span:nth-child(96) { animation-delay: calc(-95 * var(--wave-frame)); }
  .wave-row span:nth-child(97) { animation-delay: calc(-96 * var(--wave-frame)); }
  .wave-row span:nth-child(98) { animation-delay: calc(-97 * var(--wave-frame)); }
  .wave-row span:nth-child(99) { animation-delay: calc(-98 * var(--wave-frame)); }
  .wave-row span:nth-child(100) { animation-delay: calc(-99 * var(--wave-frame)); }
  .wave-row span:nth-child(101) { animation-delay: calc(-100 * var(--wave-frame)); }
  .wave-row span:nth-child(102) { animation-delay: calc(-101 * var(--wave-frame)); }
  .wave-row span:nth-child(103) { animation-delay: calc(-102 * var(--wave-frame)); }
  .wave-row span:nth-child(104) { animation-delay: calc(-103 * var(--wave-frame)); }
  .wave-row span:nth-child(105) { animation-delay: calc(-104 * var(--wave-frame)); }
  .wave-row span:nth-child(106) { animation-delay: calc(-105 * var(--wave-frame)); }
  .wave-row span:nth-child(107) { animation-delay: calc(-106 * var(--wave-frame)); }
  .wave-row span:nth-child(108) { animation-delay: calc(-107 * var(--wave-frame)); }
  .wave-row span:nth-child(109) { animation-delay: calc(-108 * var(--wave-frame)); }
  .wave-row span:nth-child(110) { animation-delay: calc(-109 * var(--wave-frame)); }
  .wave-row span:nth-child(111) { animation-delay: calc(-110 * var(--wave-frame)); }
  .wave-row span:nth-child(112) { animation-delay: calc(-111 * var(--wave-frame)); }
  .wave-row span:nth-child(113) { animation-delay: calc(-112 * var(--wave-frame)); }
  .wave-row span:nth-child(114) { animation-delay: calc(-113 * var(--wave-frame)); }
  .wave-row span:nth-child(115) { animation-delay: calc(-114 * var(--wave-frame)); }
  .wave-row span:nth-child(116) { animation-delay: calc(-115 * var(--wave-frame)); }
  .wave-row span:nth-child(117) { animation-delay: calc(-116 * var(--wave-frame)); }
  .wave-row span:nth-child(118) { animation-delay: calc(-117 * var(--wave-frame)); }
  .wave-row span:nth-child(119) { animation-delay: calc(-118 * var(--wave-frame)); }
  .wave-row span:nth-child(120) { animation-delay: calc(-119 * var(--wave-frame)); }
  .wave-row span:nth-child(121) { animation-delay: calc(-120 * var(--wave-frame)); }
  .wave-row span:nth-child(122) { animation-delay: calc(-121 * var(--wave-frame)); }
  .wave-row span:nth-child(123) { animation-delay: calc(-122 * var(--wave-frame)); }
  .wave-row span:nth-child(124) { animation-delay: calc(-123 * var(--wave-frame)); }
  .wave-row span:nth-child(125) { animation-delay: calc(-124 * var(--wave-frame)); }
  .wave-row span:nth-child(126) { animation-delay: calc(-125 * var(--wave-frame)); }
  .wave-row span:nth-child(127) { animation-delay: calc(-126 * var(--wave-frame)); }
  .wave-row span:nth-child(128) { animation-delay: calc(-127 * var(--wave-frame)); }
  .wave-row span:nth-child(129) { animation-delay: calc(-128 * var(--wave-frame)); }
  .wave-row span:nth-child(130) { animation-delay: calc(-129 * var(--wave-frame)); }
  .wave-row span:nth-child(131) { animation-delay: calc(-130 * var(--wave-frame)); }
  .wave-row span:nth-child(132) { animation-delay: calc(-131 * var(--wave-frame)); }
  .wave-row span:nth-child(133) { animation-delay: calc(-132 * var(--wave-frame)); }
  .wave-row span:nth-child(134) { animation-delay: calc(-133 * var(--wave-frame)); }
  .wave-row span:nth-child(135) { animation-delay: calc(-134 * var(--wave-frame)); }
  .wave-row span:nth-child(136) { animation-delay: calc(-135 * var(--wave-frame)); }
  .wave-row span:nth-child(137) { animation-delay: calc(-136 * var(--wave-frame)); }
  .wave-row span:nth-child(138) { animation-delay: calc(-137 * var(--wave-frame)); }
  .wave-row span:nth-child(139) { animation-delay: calc(-138 * var(--wave-frame)); }
  .wave-row span:nth-child(140) { animation-delay: calc(-139 * var(--wave-frame)); }
  .wave-row span:nth-child(141) { animation-delay: calc(-140 * var(--wave-frame)); }
  .wave-row span:nth-child(142) { animation-delay: calc(-141 * var(--wave-frame)); }
  .wave-row span:nth-child(143) { animation-delay: calc(-142 * var(--wave-frame)); }
  .wave-row span:nth-child(144) { animation-delay: calc(-143 * var(--wave-frame)); }
  .wave-row span:nth-child(145) { animation-delay: calc(-144 * var(--wave-frame)); }
  .wave-row span:nth-child(146) { animation-delay: calc(-145 * var(--wave-frame)); }
  .wave-row span:nth-child(147) { animation-delay: calc(-146 * var(--wave-frame)); }
  .wave-row span:nth-child(148) { animation-delay: calc(-147 * var(--wave-frame)); }
  .wave-row span:nth-child(149) { animation-delay: calc(-148 * var(--wave-frame)); }
  .wave-row span:nth-child(150) { animation-delay: calc(-149 * var(--wave-frame)); }
  .wave-row span:nth-child(151) { animation-delay: calc(-150 * var(--wave-frame)); }
  .wave-row span:nth-child(152) { animation-delay: calc(-151 * var(--wave-frame)); }
  .wave-row span:nth-child(153) { animation-delay: calc(-152 * var(--wave-frame)); }
  .wave-row span:nth-child(154) { animation-delay: calc(-153 * var(--wave-frame)); }
  .wave-row span:nth-child(155) { animation-delay: calc(-154 * var(--wave-frame)); }
  .wave-row span:nth-child(156) { animation-delay: calc(-155 * var(--wave-frame)); }
  .wave-row span:nth-child(157) { animation-delay: calc(-156 * var(--wave-frame)); }
  .wave-row span:nth-child(158) { animation-delay: calc(-157 * var(--wave-frame)); }
  .wave-row span:nth-child(159) { animation-delay: calc(-158 * var(--wave-frame)); }
  .wave-row span:nth-child(160) { animation-delay: calc(-159 * var(--wave-frame)); }
}
