/* ==========================================================================
   Callout — website design system
   Bartlett Software LLC
   --------------------------------------------------------------------------
   One stylesheet, no build step, no webfonts, no third-party requests.
   The palette is lifted verbatim from the app (lib/theme/app_theme.dart) so
   the site and the product read as one thing.

   CONTENTS
     01  Tokens
     02  Reset & base
     03  Utilities  (.wrap .visually-hidden .skip-link .ico .mega .scroller)
     04  Header & nav
     05  Buttons, badges, Play call-to-action
     06  Hero
     07  Sections, grid, cards
     07b Launcher  (the two-app page at the domain root)
     08  Callout note (safety disclaimer)
     09  Phone mockup
     10  Prose, doc header, table of contents
     11  Footer
     12  Breakpoints (400px, 720px, 1024px)
     13  Reduced motion
     14  Print
   ========================================================================== */

/* ===== 01  Tokens ======================================================== */

:root {
  /* The site is single-theme. Tell the UA so scrollbars, selection and other
     chrome are painted dark instead of light against #0A0A12. */
  color-scheme: dark;

  /* Brand — exact values from the app theme */
  --bg:            #0A0A12;
  --surface:       #12121E;
  --card:          #1A1A2E;
  --line:          #2A2A40;
  --purple:        #7C4DFF;
  --purple-light:  #9E6AFF;
  --orange:        #FF6D00;
  --teal:          #00BFA5;
  --red:           #FF5252;
  --green:         #00E676;
  --amber:         #FFD54F;
  --lilac:         #B39DDB;

  /* Not in the app theme. White on --purple is 4.8:1 but white on
     --purple-light is only 3.5:1, so a --purple → --purple-light gradient
     fails behind white text. Gradients that carry white text run
     --purple-deep → --purple instead (7.7:1 → 4.8:1, passing throughout). */
  --purple-deep:   #5B29D6;

  /* Text — all >= 4.5:1 on --bg and on --card */
  --text:          #E9E9F2;  /* ~15:1  body + headings                       */
  --text-dim:      #A9A9C0;  /* ~8.7:1 secondary copy                        */
  --text-muted:    #8A8AA6;  /* ~5.9:1 metadata; the smallest text allowed   */
  --link:          var(--purple-light); /* 5.6:1 — never use --purple for text */

  /* Tinted surfaces */
  --purple-wash:   rgba(124, 77, 255, 0.102);
  --purple-edge:   rgba(124, 77, 255, 0.302);
  --hairline:      rgba(255, 255, 255, 0.06);

  /* Spacing scale */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;

  /* Radii */
  --r-sm:   8px;
  --r-md:   12px;
  --r-lg:   16px;
  --r-xl:   24px;
  --r-pill: 999px;

  /* Type scale */
  --fs-xs:   0.75rem;
  --fs-sm:   0.8125rem;
  --fs-base: 1rem;
  --fs-md:   1.0625rem;
  --fs-lg:   1.25rem;
  --fs-xl:   clamp(1.375rem, 1.05rem + 1.6vw, 2rem);
  --fs-2xl:  clamp(1.75rem, 1.2rem + 2.6vw, 2.5rem);
  --fs-3xl:  clamp(2rem, 1.2rem + 4vw, 3.25rem);

  /* Font stacks — system only. A font CDN would leak every visitor's IP. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;

  /* Elevation */
  --shadow-sm:   0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md:   0 8px 24px rgba(0, 0, 0, 0.45);
  --shadow-lg:   0 24px 60px rgba(0, 0, 0, 0.55);
  --shadow-glow: 0 4px 8px rgba(124, 77, 255, 0.392); /* the app's FAB shadow */

  /* Layout */
  --gutter: 20px;
  --maxw:   1120px;

  /* Height of the sticky header. The nav wraps to two rows on very narrow
     screens, so this is bumped in section 13; anything that scrolls a target
     out from under the header offsets by it. */
  --header-h: 60px;
}

/* ===== 02  Reset & base ================================================== */

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

html {
  overflow-x: clip;            /* clip, not hidden: keeps position:sticky alive */
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  margin: 0;
  color: var(--text);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

h1 { font-size: var(--fs-3xl); font-weight: 700; letter-spacing: -0.03em; }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-md); }

p, ul, ol, figure, table, pre, blockquote { margin: 0; }

a {
  color: var(--link);
  text-decoration-color: rgba(158, 106, 255, 0.45);
  text-underline-offset: 0.18em;
}

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

img, svg, video { max-width: 100%; height: auto; }

img { display: block; }

strong, b { font-weight: 600; color: var(--text); }

code, kbd, samp, pre { font-family: var(--font-mono); font-size: 0.9em; }

hr { border: 0; border-top: 1px solid var(--line); }

::selection { background: rgba(124, 77, 255, 0.45); color: #fff; }

:focus-visible {
  outline: 2px solid var(--purple-light);
  outline-offset: 2px;
}

:focus:not(:focus-visible) { outline: none; }

/* ===== 03  Utilities ===================================================== */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap.is-narrow { max-width: 820px; }

main { flex: 1 0 auto; }

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--sp-2);
  z-index: 100;
  padding: 0.65rem 1rem;
  background: var(--purple);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-md);
}

.skip-link:focus { top: var(--sp-2); }

/* Inline icon. Sized by its own font-size unless a component overrides it. */
.ico {
  width: 1em;
  height: 1em;
  flex: none;
  fill: currentColor;
  vertical-align: -0.135em;
}

.ico.is-stroke {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Every megaphone in the app is tilted -0.297rad. Never tilt an alarm clock. */
.mega { transform: rotate(-17.02deg); }

/* The <symbol> library at the top of <body>. It must stay in the flow — a
   display:none sprite is skipped by some engines and every <use> renders
   blank — so it is collapsed to nothing instead. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Wide content scrolls inside this, never the page. */
.scroller {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.scroller > table { margin: 0; }

/* ===== 04  Header & nav ================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(10, 10, 18, 0.92);
  border-bottom: 1px solid var(--line);
}

@supports (backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px)) {
  .site-header {
    background: rgba(10, 10, 18, 0.72);
    -webkit-backdrop-filter: saturate(1.4) blur(12px);
    backdrop-filter: saturate(1.4) blur(12px);
  }
}

.nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding: 0.7rem var(--gutter);
}

.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-decoration: none;
  border-radius: var(--r-sm);
}

.nav-brand img {
  width: 28px;
  height: 28px;
  border-radius: 7px;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
}

.nav-links a {
  display: inline-block;
  padding: 0.4rem 0.6rem;
  color: var(--text-dim);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  border-radius: var(--r-sm);
}

.nav-links a:hover {
  color: var(--text);
  background: var(--hairline);
}

.nav-links a[aria-current="page"] {
  color: var(--text);
  background: var(--purple-wash);
  box-shadow: inset 0 -2px 0 var(--purple);
}

/* ===== 05  Buttons, badges, Play CTA ===================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  min-height: 48px;
  padding: 0.8rem 1.25rem;
  border: 1px solid transparent;
  border-radius: var(--r-lg);
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, background-color 0.15s ease,
              border-color 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease;
}

.btn .ico { font-size: 1.15em; }

/* No page uses .btn-primary today — the Play call-to-action below is the only
   primary action on the site. It is kept as the deliberate counterpart to
   .btn-ghost; delete it rather than leave it stale if that stops being true. */
.btn-primary {
  background: linear-gradient(to right, var(--purple-deep), var(--purple));
  color: #fff;
  box-shadow: var(--shadow-glow);
}

.btn-primary:hover { transform: translateY(-1px); filter: brightness(1.07); }
.btn-primary:active { transform: translateY(0); }

.btn-ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--text);
}

.btn-ghost:hover {
  background: var(--purple-wash);
  border-color: var(--purple-edge);
}

.badge,
.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--r-pill);
  max-width: 100%;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
}

.badge {
  background: var(--purple-wash);
  border: 1px solid var(--purple-edge);
  color: var(--purple-light);
}

.pill {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line);
  color: var(--text-dim);
}

/* The status pill is two short words and reads badly broken, so it is the one
   place that keeps nowrap. The dated pills in the legal cards must be free to
   wrap: their string is long enough to push a card past its grid column once a
   reader applies the WCAG 1.4.12 text-spacing overrides. */
.pill.is-soon { white-space: nowrap; }

.pill.is-soon::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--teal);
  box-shadow: 0 0 0 3px rgba(0, 191, 165, 0.18);
}

/* Google Play call-to-action — CSS/SVG only, never a remote badge image. */
.play-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 56px;
  padding: 0.6rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--text);
  text-decoration: none;
  transition: border-color 0.15s ease, background-color 0.15s ease,
              transform 0.15s ease;
}

.play-badge:hover {
  background: var(--card);
  border-color: var(--purple-edge);
  transform: translateY(-1px);
}

.play-badge-glyph {
  width: 26px;
  height: 26px;
  flex: none;
  color: var(--purple-light);
}

.play-badge-text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.play-badge-kicker {
  color: var(--text-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.play-badge-store {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* Applied by site.js while APP_LIVE_ON_PLAY === false. */
.play-badge.is-soon,
.btn.is-soon {
  cursor: not-allowed;
  border-style: dashed;
  opacity: 0.9;
}

.play-badge.is-soon:hover,
.btn.is-soon:hover {
  transform: none;
  filter: none;
}

/* ===== 06  Hero ========================================================== */

.hero {
  position: relative;
  padding-block: clamp(2.5rem, 7vw, 5.5rem) clamp(2.5rem, 7vw, 5rem);
  overflow: hidden;
}

/* Keep the focal points inside the clip. With a negative top offset the
   brightest part of the wash lands above .hero's overflow:hidden edge and is
   thrown away, which flattens the hero to near-black on tall desktop layouts. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 85%;
  background:
    radial-gradient(60% 60% at 70% 30%, rgba(124, 77, 255, 0.18), transparent 70%),
    radial-gradient(50% 50% at 20% 10%, rgba(0, 191, 165, 0.10), transparent 70%);
  pointer-events: none;
}

.hero > .wrap {
  position: relative;
  display: grid;
  gap: clamp(2rem, 6vw, 3.5rem);
  align-items: center;
}

.hero-copy > * + * { margin-top: var(--sp-5); }

.hero-copy h1 { line-height: 1.06; }

.hero-copy h1 em { font-style: normal; color: var(--purple-light); }

@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .hero-copy h1 em {
    background: linear-gradient(100deg, var(--purple-light), var(--teal));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.hero-copy .lede { max-width: 34rem; }

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
}

.hero-art {
  position: relative;
  display: flex;
  justify-content: center;
}

.hero-art::before {
  content: "";
  position: absolute;
  z-index: 0;
  top: 12%;
  width: 78%;
  height: 60%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(124, 77, 255, 0.30), transparent);
  filter: blur(40px);
  pointer-events: none;
}

/* ===== 07  Sections, grid, cards ========================================= */

.section { padding-block: clamp(3rem, 8vw, 6rem); }

/* Jumped to from the hero, so keep the heading clear of the sticky header. */
.section[id] { scroll-margin-top: var(--header-h); }

.section.is-alt {
  background: var(--surface);
  border-block: 1px solid var(--line);
}

.section-head {
  max-width: 62ch;
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}

.section-head > * + * { margin-top: var(--sp-3); }

.eyebrow {
  color: var(--teal);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.lede {
  color: var(--text-dim);
  font-size: var(--fs-md);
  line-height: 1.65;
}

.grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: 1fr;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  padding: var(--sp-5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

a.card {
  color: inherit;
  text-decoration: none;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

a.card:hover {
  transform: translateY(-2px);
  border-color: var(--purple-edge);
  box-shadow: var(--shadow-md);
}

.card h3 { font-size: var(--fs-md); }

.card p {
  color: var(--text-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.card-icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: var(--sp-2);
  background: var(--purple-wash);
  border: 1px solid var(--purple-edge);
  border-radius: var(--r-md);
  color: var(--purple-light);
  font-size: 22px;
}

.card-icon.is-alarm {
  background: rgba(255, 109, 0, 0.102);
  border-color: rgba(255, 109, 0, 0.30);
  color: var(--orange);
}

.card-icon.is-callout {
  background: rgba(0, 191, 165, 0.102);
  border-color: rgba(0, 191, 165, 0.30);
  color: var(--teal);
}

/* ===== 07b Launcher (site root) ========================================== */

/* web/index.html is the company front door at the domain root, not a Callout
   page: one tile per app and nothing else. It borrows the tokens and .card,
   and adds only what a tile needs — the app's own icon at full size, in place
   of the 44px glyph .card-icon draws. */

.launcher {
  display: flex;
  align-items: center;
  padding-block: clamp(3rem, 9vw, 6rem);
}

.launcher-head { text-align: center; }
.launcher-head > * + * { margin-top: var(--sp-3); }
.launcher-head h1 { margin-top: 8rem; }

/* The company logo: the monogram locked up with the name. It is the only
   place on the site the company brands itself, so it is built from tokens
   rather than one-off colours and it stays a text lockup — the words are real
   text, not part of the picture, so they are selectable, translatable and
   legible with no CSS at all. */
.brand {
  /* Full size from about 920px up; below that it shrinks just fast enough
     that BARTLETT, the mark and the gap still fit a 320px phone gutter to
     gutter, since a one-word line cannot wrap. */
  --brand-fs-a: clamp(2.25rem, 1.55rem + 4.25vw, 4rem);
  --brand-fs-b: calc(var(--brand-fs-a) * 0.375);
  --brand-line-gap: calc(var(--brand-fs-a) * 0.09);
  display: inline-flex;
  align-items: center;
  gap: calc(var(--brand-fs-a) * 0.5);
  text-align: left;
}

/* The mark is the letter alone, cut out of its tile, and it is sized to the
   words beside it: its top sits on the cap line of BARTLETT and its bottom on
   the baseline of SOFTWARE LLC. The two lines are trimmed to exactly those
   edges (text-box), so their stacked height is one cap height at each size
   plus the gap between them. Cap height scales linearly with font size, so
   1cap measured at the sum of the two sizes is the same length as the two
   cap heights added together, and the browser reads it off the real font. */
.brand-mark {
  font-size: calc(var(--brand-fs-a) + var(--brand-fs-b));
  width: auto;
  height: calc(1cap + var(--brand-line-gap));
}

.brand-name {
  display: flex;
  flex-direction: column;
  gap: var(--brand-line-gap);
}

.brand-name-a {
  color: var(--text);
  font-size: var(--brand-fs-a);
  font-weight: 800;
  letter-spacing: 0.04em;
  line-height: 1;
  text-box: trim-both cap alphabetic;
  text-transform: uppercase;
}

.brand-name-b {
  color: var(--text-dim);
  font-size: var(--brand-fs-b);
  font-weight: 600;
  letter-spacing: 0.22em;
  line-height: 1;
  text-box: trim-both cap alphabetic;
  text-transform: uppercase;
  /* Letter-spacing hangs off the last character, which would push the word
     visually left of the one above it. */
  margin-right: -0.22em;
}

.launcher-grid { margin-top: clamp(2rem, 5vw, 3rem); }

/* .card is a left-aligned column; a tile is a centred one. */
.launcher-card {
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-6) var(--sp-5);
  text-align: center;
}

.launcher-card img {
  width: clamp(84px, 20vw, 112px);
  /* An Android launcher rounds an icon to about a fifth of its width, and both
     icons are drawn edge to edge, so the corner has to be put back here. */
  border-radius: 21%;
  box-shadow: var(--shadow-md);
}

.launcher-card h2 {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* ===== 08  Callout note ================================================== */

.callout-note {
  display: flex;
  gap: 0.85rem;
  padding: var(--sp-4) var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid rgba(255, 109, 0, 0.55);
  border-radius: var(--r-md);
  color: var(--text-dim);
  font-size: 0.9375rem;
  line-height: 1.65;
}

.callout-note .ico {
  margin-top: 0.15rem;
  font-size: 1.25rem;
  color: rgba(255, 109, 0, 0.9);
}

.callout-note > div > * + * { margin-top: var(--sp-2); }

/* ===== 09  Phone mockup ================================================== */
/*
   Drawn at the app's real logical pixels (dp). --u is how big one dp is on
   screen; it shrinks on narrow viewports so a phone can never cause horizontal
   scroll. Every inner dimension is calc(N * var(--u)), so the numbers below map
   1:1 onto the Flutter widget code.

   Design size: a 411 x 870dp screen inside a 10dp bezel = 431 x 890dp total —
   the ~19.5:9 shape of the Android phones the app runs on. At the app's own
   1px-per-dp that frame is 890px tall, far too tall for a web page, so --u is
   capped below 1px and the whole device scales down as one piece.
*/

.phone {
  --u: min(0.8px, calc((100vw - (2 * var(--gutter))) / 431));
  position: relative;
  z-index: 1;
  width: calc(431 * var(--u));
  padding: calc(10 * var(--u));
  /* Anodised aluminium rail. The horizontal pass is the chamfer: both side
     faces catch the light in a band a few dp wide, the front face between them
     stays dark. `to right` keeps that band even down the whole height — a
     tilted gradient line would fade it out towards one corner. The vertical
     pass over the top is just the room light falling off. */
  background:
    linear-gradient(to bottom,
      rgba(255, 255, 255, 0.07),
      rgba(255, 255, 255, 0) 22%,
      rgba(0, 0, 0, 0) 70%,
      rgba(0, 0, 0, 0.30)),
    linear-gradient(to right,
      #7A7A90 0,
      #43435A calc(2.5 * var(--u)),
      #1E1E2A calc(8 * var(--u)),
      #17171F 50%,
      #1E1E2A calc(100% - (8 * var(--u))),
      #43435A calc(100% - (2.5 * var(--u))),
      #7A7A90 100%);
  border-radius: calc(44 * var(--u));
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.9),
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    inset 0 -1px 0 rgba(255, 255, 255, 0.10),
    var(--shadow-lg);
}

/* Power key above a volume rocker, both on the right rail — the same side a
   Pixel puts them on. They stand ~2dp proud of the frame, inside the gutter. */
.phone::before,
.phone::after {
  content: "";
  position: absolute;
  left: 100%;
  width: calc(2.5 * var(--u));
  background: linear-gradient(to right, #6E6E82, #4A4A5C 55%, #2E2E3A);
  border-radius: 0 calc(2 * var(--u)) calc(2 * var(--u)) 0;
  box-shadow: calc(1 * var(--u)) 0 calc(3 * var(--u)) rgba(0, 0, 0, 0.55);
}

.phone::before {
  top: calc(196 * var(--u));
  height: calc(58 * var(--u));
}

.phone::after {
  top: calc(276 * var(--u));
  height: calc(104 * var(--u));
}

/* 100vw counts the classic scrollbar, the column that holds the phone does
   not, so on a desktop browser with non-overlay scrollbars --u is measured
   against ~15px the phone does not have and the right bezel is sliced off by
   html{overflow-x:clip}. A container query unit measures the actual column. */
@supports (container-type: inline-size) {
  .hero-art { container-type: inline-size; }

  .phone { --u: min(0.8px, calc(100cqw / 431)); }
}

.phone-screen {
  position: relative;
  display: flex;
  flex-direction: column;
  width: calc(411 * var(--u));
  height: calc(870 * var(--u));
  overflow: hidden;
  background: var(--bg);
  border-radius: calc(34 * var(--u));
  /* The glass sits below the rail, so the bezel shades into it. */
  box-shadow:
    inset 0 0 calc(6 * var(--u)) rgba(0, 0, 0, 0.75),
    0 0 0 1px rgba(0, 0, 0, 0.9);
  /* The app bundles no font, so Android renders it in Roboto. */
  font-family: Roboto, var(--font);
  color: #fff;
  line-height: 1.25;
}

/* Punch-hole camera, centred in the status bar the way the app sees it. */
.phone-screen::after {
  content: "";
  position: absolute;
  z-index: 2;
  top: calc(8 * var(--u));
  left: 50%;
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #2B2B38, #050508 60%);
  box-shadow: 0 0 0 calc(0.75 * var(--u)) rgba(255, 255, 255, 0.10);
  transform: translateX(-50%);
}

/* Status bar */
.status-bar {
  display: flex;
  align-items: center;
  flex: none;
  height: calc(26 * var(--u));
  padding: 0 calc(18 * var(--u));
  color: rgba(255, 255, 255, 0.65);
  font-size: calc(11 * var(--u));
  font-weight: 500;
}

/* App bar */
.appbar {
  display: flex;
  align-items: center;
  flex: none;
  height: calc(56 * var(--u));
  padding-left: calc(16 * var(--u));
  background: var(--bg);
}

.appbar-menu {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(4 * var(--u));
  width: calc(24 * var(--u));
  margin-right: calc(8 * var(--u));
}

.appbar-menu i {
  height: calc(2 * var(--u));
  border-radius: calc(1 * var(--u));
  background: #fff;
}

.appbar-logo {
  display: grid;
  place-items: center;
  padding: calc(6 * var(--u));
  border-radius: calc(8 * var(--u));
  background: linear-gradient(to right, #7C4DFF, #9E6AFF);
  color: #fff;
  font-size: calc(20 * var(--u));
}

.appbar-title {
  margin-left: calc(10 * var(--u));
  font-size: calc(24 * var(--u));
  font-weight: 700;
  letter-spacing: calc(-0.5 * var(--u));
  color: #fff;
}

/* Scrollable list area */
.app-body {
  flex: 1;
  min-height: 0;
  padding-top: calc(8 * var(--u));
  overflow: hidden;
}

/* --- Routine card ------------------------------------------------------- */
/* No border in the normal state: RoutineCard overrides the theme to none.   */

.routine {
  margin: calc(6 * var(--u)) calc(16 * var(--u));
  padding: calc(16 * var(--u));
  background: var(--card);
  border-radius: calc(16 * var(--u));
}

.routine-top {
  display: flex;
  align-items: center;
  gap: calc(16 * var(--u));
}

.timeblock {
  display: flex;
  align-items: center;
  flex: none;
  width: calc(120 * var(--u));
  padding: calc(10 * var(--u)) calc(14 * var(--u));
  border: 1px solid rgba(124, 77, 255, 0.302);
  border-radius: calc(12 * var(--u));
  background: linear-gradient(135deg, rgba(124, 77, 255, 0.2), rgba(124, 77, 255, 0.102));
}

.timeblock .ico {
  font-size: calc(16 * var(--u));
  color: var(--amber);                   /* AM — sun  */
}

.timeblock .ico.is-pm { color: var(--lilac); }  /* PM — moon */

.timeblock-time {
  flex: 1;
  text-align: center;
  font-size: calc(20 * var(--u));
  font-weight: 700;
  letter-spacing: calc(-0.5 * var(--u));
  color: #fff;
}

.timeblock-mer {
  font-size: calc(12 * var(--u));
  font-weight: 600;
  letter-spacing: 0;
  color: rgba(255, 255, 255, 0.698);
}

.routine-info {
  flex: 1;
  min-width: 0;
}

.routine-name {
  overflow: hidden;
  font-size: calc(16 * var(--u));
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.routine-meta {
  display: flex;
  align-items: center;
  margin-top: calc(4 * var(--u));
  font-size: calc(13 * var(--u));
}

.count {
  display: flex;
  align-items: center;
  flex: none;
  gap: calc(4 * var(--u));
  width: calc(36 * var(--u));
}

.count .ico { font-size: calc(14 * var(--u)); }

.count.is-alarm   { color: rgba(255, 109, 0, 0.8); }
.count.is-callout { color: rgba(0, 191, 165, 0.8); }

.countdown {
  overflow: hidden;
  color: rgba(255, 255, 255, 0.706);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Material 3 switch — green when on, not purple. */
.switch {
  position: relative;
  flex: none;
  width: calc(52 * var(--u));
  height: calc(32 * var(--u));
  margin-left: calc(8 * var(--u));
  border-radius: var(--r-pill);
  background: rgba(0, 230, 118, 0.4);
}

.switch::after {
  content: "";
  position: absolute;
  top: 50%;
  right: calc(4 * var(--u));
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: 50%;
  background: var(--green);
  transform: translateY(-50%);
}

.switch.is-off {
  background: rgba(158, 158, 158, 0.302);
  box-shadow: inset 0 0 0 1px var(--line);
}

.switch.is-off::after {
  right: auto;
  left: calc(8 * var(--u));
  width: calc(16 * var(--u));
  height: calc(16 * var(--u));
  background: #9E9E9E;
}

/* Runway */
.runway {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  height: calc(12 * var(--u));
  margin-top: calc(12 * var(--u));
}

.runway .ico {
  font-size: calc(12 * var(--u));
  color: rgba(255, 109, 0, 0.745);
}

.runway .ico.is-callout { color: rgba(0, 191, 165, 0.745); }

.runway-time {
  margin-right: calc(3 * var(--u));
  font-size: calc(11 * var(--u));
  font-weight: 500;
  letter-spacing: calc(0.2 * var(--u));
  color: rgba(255, 255, 255, 0.549);
  white-space: nowrap;
}

.track {
  position: relative;
  flex: 1;
  height: calc(3 * var(--u));
  border-radius: var(--r-pill);
  background: rgba(124, 77, 255, 0.302);
}

.track-fill {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--fill, 0%);
  border-radius: var(--r-pill);
  background:
    linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.804), transparent) no-repeat,
    linear-gradient(to right, #7C4DFF, #FF6D00);
  background-size: calc(38 * var(--u)) 100%, 100% 100%;
  animation: runway-shimmer 2600ms linear infinite;
}

.track-fill::after {                      /* the "now" dot at the fill head */
  content: "";
  position: absolute;
  top: 50%;
  right: calc(-2.6 * var(--u));
  width: calc(5.2 * var(--u));
  height: calc(5.2 * var(--u));
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 calc(3 * var(--u)) rgba(255, 255, 255, 0.16);
  transform: translateY(-50%);
}

.track-cap {
  position: absolute;
  top: 50%;
  right: 0;
  width: calc(2.5 * var(--u));
  height: calc(8 * var(--u));
  border-radius: calc(1.25 * var(--u));
  background: var(--purple-light);
  transform: translateY(-50%);
}

/* Currently-playing routine: the time block breathes on a 2600ms loop. */
.routine.is-running .timeblock {
  animation: timeblock-breathe 2600ms ease-in-out infinite;
}

/* Inactive routine */
.routine.is-off .timeblock {
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.051), rgba(255, 255, 255, 0.031));
  border-color: rgba(255, 255, 255, 0.102);
}

.routine.is-off .timeblock .ico  { opacity: 0.4; }
.routine.is-off .timeblock-time  { color: rgba(255, 255, 255, 0.502); }
.routine.is-off .timeblock-mer   { color: rgba(255, 255, 255, 0.4); }
.routine.is-off .routine-name    { color: rgba(255, 255, 255, 0.6); }
.routine.is-off .count           { color: rgba(255, 255, 255, 0.302); }
.routine.is-off .runway .ico     { color: rgba(255, 255, 255, 0.251); }
.routine.is-off .runway-time     { color: rgba(255, 255, 255, 0.251); }
.routine.is-off .track           { background: rgba(255, 255, 255, 0.078); }
.routine.is-off .track-cap       { background: rgba(255, 255, 255, 0.2); }

/* --- FAB: a labelled gradient pill, not a circular + --------------------
   Drawn a little tighter than the app's 20/14 padding and 24dp glyph. At the
   scale the mockup renders at, the real proportions made the button the loudest
   thing on the page and pulled the eye off the routine list it sits over. */

.fab {
  position: absolute;
  right: calc(16 * var(--u));
  bottom: calc(36 * var(--u));
  display: inline-flex;
  align-items: center;
  gap: calc(6 * var(--u));
  padding: calc(10 * var(--u)) calc(16 * var(--u));
  background: linear-gradient(to right, #7C4DFF, #9E6AFF);
  border-radius: calc(14 * var(--u));
  box-shadow: 0 calc(4 * var(--u)) calc(8 * var(--u)) rgba(124, 77, 255, 0.392);
  color: #fff;
  font-size: calc(13 * var(--u));
  font-weight: 600;
}

.fab .ico { font-size: calc(18 * var(--u)); }

@keyframes runway-shimmer {
  from { background-position: -20% 0, 0 0; }
  to   { background-position: 120% 0, 0 0; }
}

@keyframes timeblock-breathe {
  0%, 100% {
    border-color: rgba(124, 77, 255, 0.302);
    box-shadow: 0 0 calc(8 * var(--u)) 0 rgba(124, 77, 255, 0.118);
  }
  50% {
    border-color: rgba(124, 77, 255, 0.655);
    box-shadow: 0 0 calc(20 * var(--u)) calc(1.5 * var(--u)) rgba(124, 77, 255, 0.333);
  }
}

/* --- The screenshot trio ------------------------------------------------
   Three more devices, each showing one editor screen. They are the same
   .phone frame at a smaller --u, so every dp figure below still maps 1:1 onto
   the Flutter code. .shot is the query container --u is measured against. */

.shots {
  display: grid;
  gap: clamp(2.5rem, 6vw, 3.5rem);
  grid-template-columns: 1fr;
}

.shot {
  margin: 0;
  justify-self: center;
  width: 100%;
  max-width: calc(431 * 0.75px);
}

.shot .phone {
  --u: min(0.75px, calc((100vw - (2 * var(--gutter))) / 431));
  margin-inline: auto;
}

@supports (container-type: inline-size) {
  .shot { container-type: inline-size; }

  .shot .phone { --u: min(0.75px, calc(100cqw / 431)); }
}

.shot figcaption {
  margin-top: var(--sp-5);
  text-align: center;
}

.shot figcaption h3 { margin-bottom: 0.4rem; }

.shot figcaption p {
  margin-inline: auto;
  max-width: 34ch;
  color: var(--text-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* --- Editor screens: app bar -------------------------------------------- */

.ed-bar {
  display: flex;
  align-items: center;
  flex: none;
  height: calc(56 * var(--u));
  padding: 0 calc(16 * var(--u)) 0 calc(12 * var(--u));
  background: var(--bg);
}

.ed-bar > .ico { font-size: calc(24 * var(--u)); }

.ed-title {
  flex: 1;
  margin-left: calc(20 * var(--u));
  font-size: calc(24 * var(--u));
  font-weight: 700;
  letter-spacing: calc(-0.5 * var(--u));
  color: #fff;
}

/* The Save action is a gradient stadium. It greys out until the routine has a
   name and at least one event, which is never the state a shot is in. */
.ed-save {
  flex: none;
  padding: calc(8 * var(--u)) calc(28 * var(--u));
  background: linear-gradient(to right, #7C4DFF, #9E6AFF);
  border-radius: var(--r-pill);
  color: #fff;
  font-size: calc(14 * var(--u));
  font-weight: 600;
}

/* --- Editor screens: scroll body ---------------------------------------- */

.ed-body {
  flex: 1;
  min-height: 0;
  padding: calc(16 * var(--u));
  overflow: hidden;
}

/* A filled TextField with an OutlineInputBorder. The label rides up onto the
   border once the field has a value, which is the state every shot is in. */
.field {
  position: relative;
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  padding: calc(20 * var(--u)) calc(16 * var(--u));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: calc(12 * var(--u));
}

.field > .ico {
  font-size: calc(24 * var(--u));
  color: rgba(255, 255, 255, 0.698);
}

.field-value {
  font-size: calc(22 * var(--u));
  font-weight: 700;
  color: #fff;
}

.field-label {
  position: absolute;
  top: calc(-8 * var(--u));
  left: calc(48 * var(--u));
  padding-inline: calc(4 * var(--u));
  background: var(--bg);
  color: rgba(255, 255, 255, 0.698);
  font-size: calc(13 * var(--u));
  line-height: 1.2;
}

/* Target time card */
.target {
  position: relative;
  margin-top: calc(24 * var(--u));
  padding: calc(20 * var(--u));
  background: #1B1435;
  border: 1px solid #2E2458;
  border-radius: calc(16 * var(--u));
  text-align: center;
}

.target-eyebrow {
  color: #9E6AFF;
  font-size: calc(12 * var(--u));
  font-weight: 600;
  letter-spacing: calc(1.5 * var(--u));
}

.target-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(10 * var(--u));
  margin-top: calc(8 * var(--u));
}

.target-row > .ico {
  font-size: calc(24 * var(--u));
  color: var(--amber);
}

.target-time {
  font-size: calc(48 * var(--u));
  font-weight: 700;
  letter-spacing: calc(-2 * var(--u));
  color: #fff;
}

.target-mer {
  font-size: calc(20 * var(--u));
  font-weight: 500;
  color: #BABAC0;
}

.target-hint {
  margin-top: calc(4 * var(--u));
  color: #BABAC0;
  font-size: calc(13 * var(--u));
}

.target-cal {
  position: absolute;
  right: calc(12 * var(--u));
  bottom: calc(12 * var(--u));
  display: grid;
  place-items: center;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  border: calc(1.5 * var(--u)) solid #BABAC0;
  border-radius: 50%;
  color: #BABAC0;
}

.target-cal .ico { font-size: calc(16 * var(--u)); }

.target-cal-badge {
  position: absolute;
  right: calc(-4 * var(--u));
  bottom: calc(-4 * var(--u));
  display: grid;
  place-items: center;
  width: calc(15 * var(--u));
  height: calc(15 * var(--u));
  background: #1B1435;
  border-radius: 50%;
}

.target-cal-badge .ico { font-size: calc(12 * var(--u)); }

/* Events header, with the two outlined add buttons */
.ev-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: calc(32 * var(--u));
  margin-bottom: calc(12 * var(--u));
}

.ev-title {
  font-size: calc(18 * var(--u));
  font-weight: 600;
  letter-spacing: 0;
  color: #fff;
}

.ev-adds {
  display: flex;
  gap: calc(8 * var(--u));
}

.ev-add {
  display: inline-flex;
  align-items: center;
  gap: calc(8 * var(--u));
  padding: calc(6 * var(--u)) calc(12 * var(--u));
  border: 1px solid;
  border-radius: calc(8 * var(--u));
  font-size: calc(14 * var(--u));
}

.ev-add .ico { font-size: calc(18 * var(--u)); }

.ev-add-ico {
  position: relative;
  display: inline-flex;
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
  align-items: center;
  justify-content: center;
}

.ev-add-badge {
  position: absolute;
  right: calc(-3 * var(--u));
  top: calc(-3 * var(--u));
  width: calc(12 * var(--u));
  height: calc(12 * var(--u));
  border-radius: 50%;
  display: grid;
  place-items: center;
}

.ev-add-badge .ico { font-size: calc(10 * var(--u)); color: #fff; }

.ev-add.is-alarm   { color: var(--orange); border-color: #482B25; }
.ev-add.is-alarm   .ev-add-badge { background: var(--orange); }
.ev-add.is-callout { color: var(--teal);   border-color: #153B46; }
.ev-add.is-callout .ev-add-badge { background: var(--teal); }

/* An event row. Everything in it is tinted by the event's own accent. */
.ev-tile {
  display: flex;
  align-items: center;
  margin-bottom: calc(8 * var(--u));
  padding: calc(12 * var(--u)) calc(14 * var(--u));
  border: 1px solid;
  border-radius: calc(12 * var(--u));
}

.ev-tile.is-alarm {
  background: #261E2C;
  border-color: #482B25;
  color: var(--orange);
}

.ev-tile.is-callout {
  background: #192234;
  border-color: #153B46;
  color: var(--teal);
}

.ev-icon {
  display: grid;
  place-items: center;
  flex: none;
  padding: calc(8 * var(--u));
  border-radius: calc(8 * var(--u));
  font-size: calc(20 * var(--u));
}

.ev-tile.is-alarm   .ev-icon { background: var(--orange); color: #fff; }
.ev-tile.is-callout .ev-icon { background: var(--teal); color: #fff; }

.ev-text {
  flex: 1;
  min-width: 0;
  margin-left: calc(12 * var(--u));
}

.ev-line {
  display: flex;
  align-items: baseline;
  font-size: calc(14 * var(--u));
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ev-off  { flex: none; width: calc(140 * var(--u)); }
.ev-hour { flex: none; width: calc(22 * var(--u)); text-align: right; }

.ev-sub {
  overflow: hidden;
  margin-top: calc(2 * var(--u));
  color: #BABAC0;
  font-size: calc(13 * var(--u));
  white-space: nowrap;
  text-overflow: ellipsis;
}

.ev-sub .ico {
  margin-right: calc(4 * var(--u));
  font-size: calc(14 * var(--u));
}

.ev-chip {
  flex: none;
  padding: calc(4 * var(--u)) calc(8 * var(--u));
  background: #1A1A2E;
  border: 1px solid #2A2A40;
  border-radius: calc(6 * var(--u));
  color: #BABAC0;
  font-size: calc(11 * var(--u));
  white-space: nowrap;
}

.ev-mode {
  flex: none;
  margin-left: calc(6 * var(--u));
  font-size: calc(16 * var(--u));
}

.ev-tile.is-callout .ev-mode { color: var(--teal); }
.ev-tile.is-recorded .ev-sub { color: #64B5F6; }
.ev-tile.is-recorded .ev-mode { color: #64B5F6; }

.ev-chev {
  flex: none;
  margin-left: calc(4 * var(--u));
  font-size: calc(20 * var(--u));
  color: #767682;
}

/* --- The event editor, a modal bottom sheet ----------------------------- */

.scrim {
  position: absolute;
  inset: calc(26 * var(--u)) 0 0;
  background: rgba(0, 0, 0, 0.55);
}

/* Anchored to the bottom and sized by its own content, so if a row is a dp or
   two out the sheet still meets the screen edge and the overflow clips at the
   top — which is what the real sheet does when it runs out of room. */
.sheet {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  max-height: calc(844 * var(--u));
  padding: calc(16 * var(--u)) calc(20 * var(--u)) calc(40 * var(--u));
  background: var(--card);
  border-radius: calc(20 * var(--u)) calc(20 * var(--u)) 0 0;
}

.sheet-handle {
  width: calc(40 * var(--u));
  height: calc(4 * var(--u));
  margin: 0 auto calc(12 * var(--u));
  background: rgba(255, 255, 255, 0.2);
  border-radius: calc(2 * var(--u));
}

.sheet-title {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  font-size: calc(20 * var(--u));
  font-weight: 700;
  color: #fff;
}

.sheet-title .ico { font-size: calc(24 * var(--u)); }
.sheet-title.is-alarm   .ico { color: var(--orange); }
.sheet-title.is-callout .ico { color: var(--teal); }

/* Every group in the sheet is introduced by the same 14dp label. */
.slabel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: rgba(255, 255, 255, 0.698);
  font-size: calc(14 * var(--u));
  font-weight: 500;
}

.slabel > b {
  font-weight: 600;
  color: #fff;
}

.group {
  position: relative;
  margin-top: calc(16 * var(--u));
}

.group.is-first { margin-top: calc(20 * var(--u)); }

/* The same floating label inside a sheet, where the surface behind it is the
   sheet colour and there is no prefix icon for it to clear. */
.sheet .field-label {
  left: calc(12 * var(--u));
  background: var(--card);
}

/* Hours / minutes steppers */
.nums {
  display: flex;
  gap: calc(12 * var(--u));
  margin-top: calc(8 * var(--u));
}

.num {
  display: flex;
  align-items: center;
  flex: 1;
  min-width: 0;
  padding: calc(16 * var(--u)) calc(20 * var(--u));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: calc(12 * var(--u));
}

.num-body { flex: 1; min-width: 0; }

.num-label {
  display: block;
  color: rgba(255, 255, 255, 0.4);
  font-size: calc(13 * var(--u));
}

.num-value {
  display: block;
  font-size: calc(48 * var(--u));
  font-weight: 700;
  line-height: 1.15;
  color: #fff;
}

.num-steps {
  display: flex;
  flex-direction: column;
  flex: none;
}

.num-steps .ico {
  box-sizing: content-box;
  padding: calc(6 * var(--u));
  font-size: calc(32 * var(--u));
  color: rgba(255, 255, 255, 0.698);
}

.num-steps .ico.is-off { color: rgba(255, 255, 255, 0.149); }

/* AI Voice / Record segmented button */
.seg {
  display: flex;
  overflow: hidden;
  height: calc(40 * var(--u));
  border: 1px solid var(--line);
  border-radius: calc(12 * var(--u));
}

.seg-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(8 * var(--u));
  flex: 1;
  color: rgba(255, 255, 255, 0.698);
  font-size: calc(14 * var(--u));
  font-weight: 500;
}

.seg-btn .ico { font-size: calc(18 * var(--u)); }

.seg-btn + .seg-btn { border-left: 1px solid var(--line); }

.seg-btn.is-on {
  background: var(--purple);
  color: #fff;
}

/* Alarm sound row, and the vibrate toggle beside it */
.row-end {
  display: flex;
  align-items: flex-end;
  gap: calc(12 * var(--u));
  margin-top: calc(16 * var(--u));
}

.row-end > .group {
  flex: 1;
  min-width: 0;
  margin-top: 0;
}

.picker {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  margin-top: calc(8 * var(--u));
  padding: calc(14 * var(--u)) calc(16 * var(--u));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: calc(12 * var(--u));
  color: #fff;
  font-size: calc(16 * var(--u));
}

.picker .ico { font-size: calc(22 * var(--u)); }
.picker .ico.is-alarm { color: var(--orange); }
.picker .ico.is-chev  { color: rgba(255, 255, 255, 0.4); }

.picker-name {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.toggle {
  flex: none;
  padding: calc(14 * var(--u)) calc(18 * var(--u));
  background: rgba(255, 109, 0, 0.149);
  border: 1px solid var(--orange);
  border-radius: calc(12 * var(--u));
  color: var(--orange);
  font-size: calc(22 * var(--u));
  line-height: 0;
}

/* The message field, with the voice picker stretched alongside it */
.tts {
  display: flex;
  align-items: stretch;
  gap: calc(8 * var(--u));
}

.tts-field {
  flex: 1;
  min-width: 0;
  padding: calc(14 * var(--u)) calc(16 * var(--u));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: calc(12 * var(--u));
  color: #fff;
  font-size: calc(16 * var(--u));
  line-height: 1.25;
}

.voice {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: none;
  padding: calc(4 * var(--u)) calc(12 * var(--u));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: calc(8 * var(--u));
  color: #fff;
  font-size: calc(13 * var(--u));
}

.voice .ico {
  margin-bottom: calc(2 * var(--u));
  font-size: calc(24 * var(--u));
  color: var(--teal);
}

/* Audition link under a field */
.preview {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(4 * var(--u));
  margin-top: calc(8 * var(--u));
  padding: calc(8 * var(--u));
  font-size: calc(14 * var(--u));
  font-weight: 500;
}

.preview .ico { font-size: calc(18 * var(--u)); }
.preview.is-alarm   { color: var(--orange); }
.preview.is-callout { color: var(--teal); }

/* Sliders. A 4dp track with a 20dp handle, ticked at every division exactly
   as the app's SliderTheme draws them. --at is where the handle sits. */
.slider-row {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  height: calc(48 * var(--u));
}

.slider-row > .ico {
  flex: none;
  font-size: calc(20 * var(--u));
  color: rgba(255, 255, 255, 0.698);
}

.slider-row > .ico.is-off { color: rgba(255, 255, 255, 0.302); }

.slider {
  position: relative;
  flex: 1;
  height: calc(4 * var(--u));
  border-radius: var(--r-pill);
  background: var(--line);
}

.slider.is-alarm   { color: var(--orange); }
.slider.is-callout { color: var(--teal); }
.slider.is-purple  { color: var(--purple); }

.slider-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--at);
  border-radius: var(--r-pill);
  background: currentColor;
}

.slider-thumb {
  position: absolute;
  top: 50%;
  left: var(--at);
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  border-radius: 50%;
  background: currentColor;
  transform: translate(-50%, -50%);
}

.slider-ticks {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-inline: calc(3 * var(--u));
}

.slider-ticks i {
  width: calc(6 * var(--u));
  height: calc(6 * var(--u));
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.298);
}

.slider-ticks i.is-past { background: rgba(255, 255, 255, 0.698); }

.ticks {
  display: flex;
  justify-content: space-between;
  color: rgba(255, 255, 255, 0.4);
  font-size: calc(11 * var(--u));
}

.ticks b {
  font-weight: 600;
  color: #fff;
}

/* Centred caption under a slider — the fade-in duration and its audition. */
.slider-caption {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(16 * var(--u));
  padding-bottom: calc(8 * var(--u));
  color: rgba(255, 255, 255, 0.6);
  font-size: calc(13 * var(--u));
}

.slider-caption .preview { margin-top: 0; padding: 0; }

/* The sheet's commit button */
.sheet-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(52 * var(--u));
  margin-top: calc(24 * var(--u));
  border-radius: calc(12 * var(--u));
  color: #fff;
  font-size: calc(16 * var(--u));
  font-weight: 600;
}

.sheet-btn.is-alarm   { background: var(--orange); }
.sheet-btn.is-callout { background: var(--teal); }

/* ===== 10  Prose, doc header, TOC ======================================= */

.doc-header {
  padding-bottom: var(--sp-5);
  margin-bottom: var(--sp-6);
  border-bottom: 1px solid var(--line);
}

.doc-header > * + * { margin-top: var(--sp-3); }

.doc-header h1 { font-size: var(--fs-2xl); }

.doc-updated {
  color: var(--text-muted);
  font-size: 0.9375rem;
}

/* The support address and mailing address on contact.html, which are PNGs
   rather than text so that address harvesters find nothing to take. Each asset
   is drawn at twice the display size to stay sharp on a 2x screen. */
.contact-text img {
  max-width: 100%;
  height: auto;
}
.contact-text img[width="720"]  { width: 360px; }
.contact-text img[width="1260"] { width: 630px; }

/* Inline contact images inside the legal pages' prose, rendered at 2x for
   retina and displayed at half their pixel size to match body text. */
.contact-inline img {
  max-width: 100%;
  height: auto;
}
.contact-inline img[width="640"] { width: 320px; }
.contact-inline img[width="920"] { width: 460px; }

/* contact.html carries no nav — it is shared by every app we publish, so it
   shows none of their branding — and this is the one way back out of it. */
.page-return {
  margin-top: var(--sp-7);
  text-align: center;
  font-size: var(--fs-sm);
}

.page-return a {
  text-decoration: none;
}

.toc {
  padding: var(--sp-4) var(--sp-5);
  margin-bottom: var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.toc-title {
  margin-bottom: var(--sp-3);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.toc ol {
  padding-left: 1.35rem;
  margin: 0;
}

.toc li { margin-top: 0.4rem; }

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

.toc a {
  color: var(--text-dim);
  text-decoration: none;
}

.toc a:hover {
  color: var(--text);
  text-decoration: underline;
}

.prose {
  max-width: 72ch;
  color: var(--text-dim);
  font-size: var(--fs-base);
  line-height: 1.7;
}

.prose > * + * { margin-top: 1.15em; }

/* Three real steps. At >=720px .prose body text is --fs-md, so an h3 set at
   --fs-md read as a bolded paragraph rather than a subsection heading.
   scroll-margin-top tracks the sticky header: a fixed 5rem was smaller than
   the two-row header on very narrow screens and dropped every TOC target
   behind it. */
.prose h2 {
  margin-top: 2.2em;
  font-size: 1.4rem;
  scroll-margin-top: calc(var(--header-h) + 1.25rem);
}

.prose h3 {
  margin-top: 1.8em;
  font-size: 1.15rem;
  scroll-margin-top: calc(var(--header-h) + 1.25rem);
}

.prose h2 + p,
.prose h3 + p,
.prose h2 + ul,
.prose h3 + ul,
.prose h2 + ol,
.prose h3 + ol { margin-top: 0.7em; }

.prose ul,
.prose ol { padding-left: 1.35rem; }

.prose li + li { margin-top: 0.45em; }

.prose li::marker { color: var(--purple-light); }

.prose ol li::marker { color: var(--text-muted); }

.prose a { font-weight: 500; }

.prose hr { margin-block: 2.5em; }

.prose table {
  width: 100%;
  min-width: 30rem;
  border-collapse: collapse;
  font-size: 0.9375rem;
  text-align: left;
}

.prose th,
.prose td {
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.prose th {
  background: rgba(255, 255, 255, 0.03);
  color: var(--text);
  font-weight: 600;
}

.prose tr:last-child td { border-bottom: 0; }

.prose pre {
  padding: var(--sp-4);
  overflow-x: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  line-height: 1.5;
}

.prose code {
  padding: 0.1em 0.35em;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 5px;
  color: var(--text);
  word-break: break-word;
}

.prose pre code {
  padding: 0;
  background: none;
}

.prose blockquote {
  padding-left: var(--sp-4);
  border-left: 3px solid var(--purple-edge);
}

.prose details {
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.prose summary {
  cursor: pointer;
  color: var(--text);
  font-weight: 600;
}

.prose summary:focus-visible { outline-offset: 4px; }

.prose details[open] summary { margin-bottom: var(--sp-3); }

.prose address {
  font-style: normal;
  color: var(--text-dim);
}

/* ===== 11  Footer ======================================================== */

.site-footer {
  flex: none;
  padding-block: clamp(2.5rem, 6vw, 4rem) var(--sp-6);
  background: var(--surface);
  border-top: 1px solid var(--line);
}

/* The footer reads as one more alternating band, so it has to take the
   opposite tone from whatever section ends the page: --surface against a
   plain --bg section, --bg when the page already ends on an .is-alt band
   (404.html) that is --surface itself. */
main:has(> .section.is-alt:last-child) + .site-footer {
  background: var(--bg);
}

.footer-cols {
  display: grid;
  gap: var(--sp-6);
  grid-template-columns: 1fr;
}

.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-decoration: none;
}

.footer-brand img {
  width: 26px;
  height: 26px;
  border-radius: 6px;
}

.footer-col p {
  margin-top: var(--sp-3);
  max-width: 32ch;
  color: var(--text-dim);
  font-size: 0.9375rem;
}

.footer-head {
  margin-bottom: var(--sp-3);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.footer-col ul {
  display: grid;
  gap: 0.55rem;
  padding: 0;
  list-style: none;
}

.footer-col a {
  color: var(--text-dim);
  font-size: 0.9375rem;
  text-decoration: none;
}

.footer-col a:hover {
  color: var(--text);
  text-decoration: underline;
}

.footer-fine {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin-top: var(--sp-7);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* The root page's footer is the fine print alone, with no columns above it to
   be ruled off from. */
.footer-fine.is-flush {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
  justify-content: center;
}

.footer-fine a {
  color: inherit;
  text-decoration: none;
}

/* ===== 12  Breakpoints =================================================== */

/* Below roughly 360px the brand and the nav links no longer fit on one line
   and .nav wraps, taking the sticky header from 60px to ~96px. Anchor offsets
   follow it. The bound is set wide of the measured wrap point on purpose:
   overshooting only leaves a heading a little lower on the screen, while
   undershooting hides it under the header. */
@media (max-width: 400px) {
  :root { --header-h: 96px; }
}

@media (min-width: 720px) {
  :root { --gutter: 24px; }

  .prose { font-size: var(--fs-md); }

  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-5); }

  .footer-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .toc ol { columns: 2; column-gap: var(--sp-6); }

  .toc li { break-inside: avoid; }
}

@media (min-width: 1024px) {
  :root { --gutter: 32px; }

  /* 431dp of device at the 0.8px-per-dp the mockup is capped to. */
  .hero > .wrap { grid-template-columns: minmax(0, 1fr) 345px; }

  .hero-art { justify-content: flex-end; }

  .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .grid.is-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .shots { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .footer-cols { grid-template-columns: 2fr 1fr 1fr; }
}

/* ===== 13  Reduced motion ================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

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

  .btn:hover,
  a.card:hover,
  .play-badge:hover { transform: none; }
}

/* ===== 14  Print ========================================================= */

@media print {
  /* Almost every colour on the site comes from a token, and each of those
     wins over the inherited body colour. Re-pointing the tokens converts the
     whole page to ink on paper in one place — headings, ledes, cards, pills
     and eyebrows included, not just .prose. Anything below this that hard-codes
     a colour or a gradient has to be reset by hand. */
  :root {
    color-scheme: light;

    --bg:          #fff;
    --surface:     #fff;
    --card:        #fff;
    --line:        #999;
    --hairline:    #999;
    --purple:      #000;
    --purple-deep: #000;
    --purple-light:#000;
    --teal:        #000;
    --text:        #000;
    --text-dim:    #000;
    --text-muted:  #333;
    --link:        #000;
    --purple-wash: transparent;
    --purple-edge: #999;
    --shadow-sm:   none;
    --shadow-md:   none;
    --shadow-lg:   none;
    --shadow-glow: none;
  }

  html,
  body {
    background: #fff !important;
    color: #000 !important;
  }

  /* Gradient text: the clip leaves color:transparent behind, so on paper the
     emphasised words print blank unless the fill is restored. */
  .hero-copy h1 em {
    background: none !important;
    color: #000 !important;
  }

  .card,
  .card-icon,
  .badge,
  .pill {
    background: none !important;
    color: #000 !important;
  }

  .card-icon { border-color: #999 !important; }

  .callout-note .ico { color: #000 !important; }

  .site-header,
  .site-footer,
  .skip-link,
  .toc,
  .sprite,
  .shots,
  .phone,
  .hero-art,
  .play-badge,
  .btn { display: none !important; }

  .wrap { max-width: none; padding-inline: 0; }

  .prose,
  .prose h2,
  .prose h3,
  .prose strong,
  .doc-header h1,
  .doc-updated { color: #000 !important; }

  .prose { max-width: none; font-size: 11pt; line-height: 1.5; }

  .prose a { color: #000 !important; text-decoration: underline; }

  .prose a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    word-break: break-all;
  }

  .doc-header,
  .prose hr,
  .prose th,
  .prose td,
  .scroller { border-color: #999 !important; }

  .prose th { background: #eee !important; }

  .prose table { min-width: 0; }

  .prose h2,
  .prose h3 { break-after: avoid; page-break-after: avoid; }

  .prose p,
  .prose li { orphans: 3; widows: 3; }

  .callout-note {
    background: none !important;
    border: 1px solid #999 !important;
    color: #000 !important;
  }

  .contact-inline img,
  .contact-text img { filter: brightness(0); }
}
