/*
  KOVE · THE SITE'S ONE STYLESHEET (redesign 2026-09-24).

  Two canvases, one system. The HOME is the app's own dark chat, drawn with the app's own shapes,
  because the home page IS a conversation with Kove. Every SECONDARY page (how it works, the
  questions, the guide, the Yazio comparison, privacy, terms) is a light reading canvas that opens on
  a solid Kove-lime hero. What ties them together is deliberate and short: the same dark header on
  every page, the same fonts, the same phone frame around the same real screenshots, and the same
  solid-lime close at the foot of every page before the same dark footer.

  The tokens in the first :root block are MIRRORED from web/src/index.css and gated by
  web/scripts/check-site-tokens.mjs: if the two disagree the app is right and this file is stale.
  Site-only tokens live in the second :root block under names the app does not use.

  The CSP in _headers carries no 'unsafe-inline', so nothing on this site may use a style
  attribute or an inline <style>. Everything visual is here; anything computed is set through the
  CSSOM from a script, or drawn as SVG presentation attributes.
*/

@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("./fonts/inter.woff2") format("woff2");
}
@font-face {
  font-family: "Space Grotesk Variable";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("./fonts/space-grotesk.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono Variable";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("./fonts/jetbrains-mono.woff2") format("woff2");
}

:root {
  /* colour, mirrored from web/src/index.css */
  --background: #0a0b0a;
  --foreground: #f2f4f2;
  --card: #171917;
  --panel: #1e211e;
  --accent: #242824;
  --muted: #151715;
  --muted-foreground: #8e968f;
  --primary: #7ffa88;
  --primary-foreground: #07130a;
  --destructive: #f25e50;
  --border: #343933;
  --input: #4a514a;
  --selected: #233425;
  --selection: #335f36;
  --goal-water: #3d7de0;
  --goal-sleep: #9da4f8;
  --goal-steps: #f291a8;

  /* shape: 12px base, laddered */
  --radius: 0.75rem;
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
  --radius-2xl: 1rem;

  /* type */
  --font-display: "Space Grotesk Variable", "Inter Variable", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "Inter Variable", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, monospace;
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;

  /* motion: ease-in deliberately absent */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* the app's resting elevation */
  --shadow-resting: inset 0 1px 0 0 color-mix(in oklab, var(--foreground) 5%, transparent),
    0 1px 2px 0 rgb(0 0 0 / 0.4), 0 12px 32px -16px rgb(0 0 0 / 0.55);
}

@media (pointer: coarse) {
  :root {
    --text-xs: 0.875rem;
    --text-sm: 1rem;
  }
}

/* Site-only tokens. None of these names exists in the app. */
:root {
  --frame: 46rem; /* the home's thread column; secondary pages widen it */
  --gutter: 1rem;
  --header-h: 3.75rem;
  --paper: #f3f4ee; /* the ticket pieces */
  --paper-ink: #1a1c1a;
  /* the light reading canvas of every secondary page */
  --light-bg: #f6f7f5;
  --light-card: #ffffff;
  --light-ink: #0f120f;
  --light-body: #2b322c;
  --light-soft: #4f5850;
  --light-faint: #5f6860;
  --light-line: #dfe3de;
  --light-tint: #e8efe6;
  --light-link: #1a6b27;
  --shadow-light: 0 1px 2px rgb(15 18 15 / 0.06), 0 18px 40px -26px rgb(15 18 15 / 0.35);
}

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

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  background: var(--background);
  color: var(--foreground);
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img,
svg {
  display: block;
  max-width: 100%;
}
::selection {
  background: var(--selection);
  color: var(--foreground);
}
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: 0.25rem;
}
.ico {
  width: 1em;
  height: 1em;
  flex: none;
  display: inline-block;
  vertical-align: -0.125em;
}
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.skip {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 100;
  background: var(--primary);
  color: var(--primary-foreground);
  padding: 0.6rem 1rem;
  border-radius: 0.5rem;
  font-weight: 600;
  text-decoration: none;
}
.skip:focus {
  top: 0.75rem;
}
.nums {
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ header, every page */

.topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--background);
  border-bottom: 1px solid var(--border);
}
.topbar > .sheet {
  max-width: calc(var(--frame) + 2 * var(--gutter));
  margin: 0 auto;
  height: var(--header-h);
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.wordmark {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--foreground);
  text-decoration: none;
  font: 600 1.125rem/1 var(--font-display);
  letter-spacing: -0.01em;
  flex: none;
}
.wordmark .mark {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 18.75%;
}
/* The home's lockup is a LOCKUP: the tile is exactly as tall as the words, its top edge on the
   cap line of "Kove" and its bottom edge on the baseline of the status. Measured in Chrome with
   the fonts' own metrics: the gap between the two lines sets the ink's height (28px, the tile's),
   and the 1px of padding centres that ink on the tile, since flex centres the line boxes and the
   display face carries more room above its caps than the status carries below its baseline.
   Change either type size and re-measure, because both numbers follow from the fonts. */
.wordmark-text:has(> .wordmark-sub) {
  padding-top: 1px;
}
.wordmark-sub {
  display: block;
  font: 400 0.75rem/1.2 var(--font-sans);
  color: var(--muted-foreground);
  letter-spacing: 0;
  margin-top: 0.09rem;
}
/* middle puts the dot's centre at the baseline plus half the x-height, which is the centre of
   the lowercase letters it sits beside. */
.online {
  display: inline-block;
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: var(--primary);
  margin-right: 0.35rem;
  vertical-align: middle;
}
.topnav {
  display: none;
  gap: 0.125rem;
  margin-left: 0.75rem;
}
.topnav a {
  white-space: nowrap;
  color: var(--muted-foreground);
  text-decoration: none;
  font-size: 0.875rem;
  padding: 0.5rem 0.7rem;
  border-radius: 0.5rem;
  transition: color 150ms var(--ease-out), background-color 150ms var(--ease-out);
}
.topnav a:hover,
.topnav a[aria-current="page"] {
  color: var(--foreground);
  background: var(--card);
}
.topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.topbar .topbar-signin {
  color: var(--muted-foreground);
  font-size: 0.875rem;
  text-decoration: none;
  padding: 0.5rem 0.4rem;
  display: none;
}
.topbar .topbar-signin:hover {
  color: var(--foreground);
}
.topbar-cta {
  height: 2.25rem;
  padding: 0 0.9rem;
  font-size: 0.8125rem;
  border-radius: 0.5rem;
  white-space: nowrap;
}
/* The language switch is two LINKS, since the language is the URL, so any motion has to cross a
   page load. The lit pill is ONE element under both labels, placed by whichever link is marked
   current, which is what lets it travel: on a browser with cross-document View Transitions it
   slides from the language you left to the one you picked as the new page arrives (the rules at
   the end of this block). The two columns are equal so a translate of 100% lands exactly on the
   other label whatever its width. */
.langswitch {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--border);
  border-radius: 99px;
  padding: 2px;
  flex: none;
}
.lang-thumb {
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 2px;
  width: calc(50% - 2px);
  border-radius: 99px;
  background: var(--selected);
  pointer-events: none;
}
.langswitch:where(:has(> .lang[data-lang="it"][aria-current="true"])) > .lang-thumb {
  translate: 100% 0;
}
.lang {
  /* Positioned so it paints above the pill, which comes first in the markup. */
  position: relative;
  display: grid;
  place-items: center;
  min-width: 2.35rem;
  height: 1.9rem;
  padding: 0 0.55rem;
  border-radius: 99px;
  font: 500 0.8125rem/1 var(--font-sans);
  color: var(--muted-foreground);
  text-decoration: none;
}
.lang:hover {
  color: var(--foreground);
}
.lang[aria-current="true"] {
  color: var(--primary);
}
.lang:not([aria-current="true"]):active {
  color: var(--foreground);
  scale: 0.94;
}
@media (prefers-reduced-motion: no-preference) {
  .lang {
    transition: color 150ms var(--ease-out), scale 150ms var(--ease-out);
  }
  /* Cross-document View Transitions, opted into by every page of the site. Only the switch is
     named, and the page itself swaps exactly as it would with none (the root's cross-fade is
     switched off), so the one thing that moves is the thing you touched. boot.js skips every
     navigation that did not start on the switch: the switch sits at a different spot in the
     header on different pages, so the home to the FAQ would otherwise glide it sideways. The
     names wait for its .js class, so with no script nothing moves. Chrome 126+ and Safari 18.2+;
     anything else swaps instantly, which is also what reduced motion gets. */
  @view-transition {
    navigation: auto;
  }
  .js .lang-thumb {
    view-transition-name: lang-thumb;
  }
  .js .lang[data-lang="en"] {
    view-transition-name: lang-en;
  }
  .js .lang[data-lang="it"] {
    view-transition-name: lang-it;
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
    mix-blend-mode: normal;
  }
  ::view-transition-group(lang-thumb) {
    animation-duration: 280ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
  ::view-transition-old(lang-en),
  ::view-transition-new(lang-en),
  ::view-transition-old(lang-it),
  ::view-transition-new(lang-it) {
    animation-duration: 220ms;
    animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
  }
}
@media (min-width: 30rem) {
  .topbar .topbar-signin {
    display: inline;
  }
}
@media (min-width: 56rem) {
  .topnav {
    display: flex;
  }
}
@media (max-width: 25rem) {
  .wordmark-text {
    display: none;
  }
}
/* `.topbar` in front, or `.btn`'s own display (later in this file, same specificity) wins and the
   button never hides: at 320px the Italian label pushed the header 6px past the screen. The close
   band at the foot of every page still carries the waitlist. */
@media (max-width: 21rem) {
  .topbar .topbar-cta {
    display: none;
  }
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 2.75rem;
  padding: 0 1.25rem;
  border-radius: 0.625rem;
  border: 1px solid transparent;
  font: 600 0.9375rem/1 var(--font-sans);
  text-decoration: none;
  cursor: pointer;
  transition: transform 160ms var(--ease-out), background-color 160ms var(--ease-out);
}
.btn:active {
  transform: scale(0.97);
}
.btn-primary,
.btn-outline.topbar-cta {
  background: var(--primary);
  color: var(--primary-foreground);
}
.btn-primary:hover,
.btn-outline.topbar-cta:hover {
  background: color-mix(in oklab, var(--primary) 88%, white);
}
.btn-ink {
  background: var(--primary-foreground);
  color: var(--primary);
}
.btn-ink:hover {
  background: #12291a;
}
.btn-sm {
  height: 2.25rem;
  padding: 0 0.9rem;
  font-size: 0.8125rem;
  border-radius: 0.5rem;
}
.btn:disabled {
  opacity: 0.6;
  cursor: default;
  transform: none;
}
.btn-lg {
  height: 3.25rem;
  padding: 0 1.6rem;
  font-size: 1.0625rem;
  border-radius: 0.7rem;
}
.btn .ico {
  width: 1.05em;
  height: 1.05em;
}

/* ------------------------------------------------------------------ the lime close, every page */

.band-lime,
.page .band-close {
  background: var(--primary);
  color: var(--primary-foreground);
}
.band-lime {
  padding: clamp(3.5rem, 9vw, 6rem) var(--gutter) clamp(4rem, 9vw, 6.5rem);
}
.band-lime .inner {
  max-width: var(--frame);
  margin: 0 auto;
}
.band-lime .from {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font: 600 0.875rem/1 var(--font-sans);
  margin: 0 0 1.25rem;
}
.band-lime .from img {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 0.3rem;
  box-shadow: 0 0 0 1.5px var(--primary-foreground);
}
.band-lime h2,
.page .band-close h2 {
  font: 700 clamp(2.6rem, 8vw, 5.4rem)/0.93 var(--font-display);
  letter-spacing: -0.04em;
  margin: 0 0 1.75rem;
  max-width: 13ch;
  text-wrap: balance;
}
.band-lime .close-sub {
  margin: -0.75rem 0 1.75rem;
  font: 500 clamp(1.05rem, 2.2vw, 1.3rem)/1.35 var(--font-sans);
  color: color-mix(in oklab, var(--primary-foreground) 82%, var(--primary));
}
/* The waitlist stays the band's one action; signing in sits beside it as a line of ink, for the
   reader who already has an invite and scrolled this far. The slop takes the target past 44px
   without moving the text. */
.close-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
}
.close-signin {
  position: relative;
  color: var(--primary-foreground);
  font: 500 0.9375rem/1.3 var(--font-sans);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}
.close-signin::after {
  content: "";
  position: absolute;
  inset: -0.75rem -0.5rem;
}
.close-signin:hover {
  text-decoration-thickness: 2px;
}
.band-lime .terms {
  margin: 1.1rem 0 0;
  font: 500 0.8125rem/1.55 var(--font-mono);
  max-width: 40rem;
}
.band-lime :focus-visible,
.page .band-hero :focus-visible,
.page .band-close :focus-visible {
  outline-color: var(--primary-foreground);
}
.band-lime ::selection,
.page .band-hero ::selection,
.page .band-close ::selection {
  background: var(--primary-foreground);
  color: var(--primary);
}

/* ------------------------------------------------------------------ footer, every page */

/* One footer on all fourteen documents, in three tiers: who this is (the mark and the tagline), where
   to go (three labelled groups of links), and what to know (the disclosures, under a hairline, in two
   quiet columns at a readable measure). The credit closes it. */
.footer {
  background: var(--background);
  color: var(--muted-foreground);
  padding: clamp(3rem, 7vw, 4.5rem) 0 3rem;
}
.footer > .sheet {
  max-width: calc(var(--frame) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.home .footer > .sheet {
  max-width: calc(62rem + 2 * var(--gutter));
}
.footer-top {
  display: grid;
  grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
  gap: 2.5rem clamp(2.5rem, 7vw, 6rem);
  align-items: start;
}
.footer-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font: 600 1.25rem/1 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--foreground);
  text-decoration: none;
}
.footer-mark img {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 18.75%;
}
.footer-tag {
  margin: 0.9rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: color-mix(in oklab, var(--foreground) 82%, var(--background));
}
.footer-cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2rem;
}
.footer-h {
  margin: 0 0 0.85rem;
  font: 600 0.8125rem/1.3 var(--font-sans);
  color: var(--foreground);
}
.footer-col ul {
  display: grid;
  gap: 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.footer-col a {
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--muted-foreground);
  text-decoration: none;
}
.footer-col a:hover {
  color: var(--foreground);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.footer-col a[aria-current="page"] {
  color: var(--foreground);
}
.footer-notes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.8rem clamp(2rem, 5vw, 3.5rem);
  margin: clamp(2.5rem, 6vw, 3.5rem) 0 0;
  padding: 1.75rem 0 0;
  border-top: 1px solid var(--border);
}
.footer-notes p {
  margin: 0;
  max-width: 34rem;
  font-size: 0.75rem;
  line-height: 1.65;
}
.footer-base {
  margin: 1.75rem 0 0;
  font-size: 0.75rem;
}
.footer-base a {
  color: var(--foreground);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.footer-base a:hover,
.footer-mark:hover {
  color: var(--primary);
}
@media (max-width: 56rem) {
  .footer-top {
    grid-template-columns: minmax(0, 1fr);
  }
  .footer-tag {
    max-width: 28rem;
  }
}
@media (max-width: 40rem) {
  .footer-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.75rem 1.5rem;
  }
  /* The long column takes the left side whole, and the two short ones stack beside it, so the
     right column has no hole under Yazio. */
  .footer-col:first-child {
    grid-row: span 2;
  }
  .footer-notes {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ------------------------------------------------------------------ a photo of a label */

/* The reader's own picture, DRAWN rather than shot: a yogurt pot's label close up, a little crooked
   (1.5deg: at 3.5 each value sat a full row above its own label) and shaded by the pot's curve, the way a phone photo of one comes out. Drawn so its words exist in
   both languages and stay readable at any size: everything inside is sized off the frame's width.
   It sits right-aligned above its caption, where a picture a person sends sits in the app. */
.k-photo {
  position: relative;
  width: min(14.5rem, 72%);
  aspect-ratio: 4 / 5;
  margin: 0 0 0.5rem auto;
  overflow: hidden;
  border-radius: 1rem;
  container-type: inline-size;
  background: radial-gradient(130% 95% at 18% 8%, color-mix(in oklab, var(--paper) 20%, var(--panel)), var(--background) 72%);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--primary) 15%, transparent), 0 20px 40px -26px rgb(0 0 0 / 0.9);
}
.k-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(118deg, rgb(255 255 255 / 0.1) 0%, transparent 34%),
    radial-gradient(120% 70% at 50% 118%, rgb(0 0 0 / 0.4), transparent 62%);
}
.lb {
  position: absolute;
  top: 6%;
  bottom: -8%;
  left: 7%;
  right: 5%;
  rotate: -1.5deg;
  padding: 7cqw 7cqw 6cqw 7cqw;
  border-radius: 2cqw;
  color: var(--paper-ink);
  background: linear-gradient(90deg, color-mix(in oklab, var(--paper) 76%, var(--background)) 0%, var(--paper) 14%, var(--paper) 72%, color-mix(in oklab, var(--paper) 84%, var(--background)) 100%);
  box-shadow: -2cqw 3cqw 7cqw rgb(0 0 0 / 0.45);
}
.lb p {
  margin: 0;
}
.lb-name {
  font: 700 10.5cqw/1 var(--font-display);
  letter-spacing: -0.02em;
}
.lb-sub {
  margin-top: 1.8cqw !important;
  font: 500 4.6cqw/1.2 var(--font-sans);
  color: color-mix(in oklab, var(--paper-ink) 72%, var(--paper));
}
.lb-ing {
  margin-top: 3.6cqw !important;
  font: 400 3.7cqw/1.35 var(--font-sans);
}
.lb-ing b {
  font-weight: 700;
}
.lb-table {
  width: 100%;
  margin-top: 3.4cqw;
  border-collapse: collapse;
  font: 400 4.1cqw/1.2 var(--font-sans);
}
.lb-table caption {
  caption-side: top;
  text-align: left;
  padding-bottom: 1.4cqw;
  border-bottom: 1.1cqw solid var(--paper-ink);
  font: 700 4.3cqw/1.2 var(--font-sans);
}
.lb-table tr {
  border-bottom: 0.35cqw solid color-mix(in oklab, var(--paper-ink) 28%, transparent);
}
.lb-table th,
.lb-table td {
  padding: 1.05cqw 0;
}
.lb-table th {
  text-align: left;
  font-weight: 600;
}
.lb-table td {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.lb-table tr.sub th {
  padding-left: 3cqw;
  font-weight: 400;
}

/* What the save leaves, in the app's own two shapes: the "Food" line (a pot, the word, and the
   food's name drawn as the app's green link to it, like the training plan's line) and the food
   card, whose tile is a small copy of the label because a saved food keeps the picture it was
   saved from. */
.k-saved > .ico {
  color: var(--primary);
}
.k-food {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  max-width: 22rem;
}
.k-food-head {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}
.k-food-tile {
  position: relative;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  overflow: hidden;
  border-radius: 0.5rem;
  background: var(--panel);
  box-shadow: 0 0 0 1px var(--border);
}
.k-food-tile::before {
  content: "";
  position: absolute;
  inset: 12% 8% -10% 14%;
  rotate: -1.5deg;
  border-radius: 2px;
  background: var(--paper);
}
.k-food-tile i {
  position: absolute;
  left: 30%;
  height: 2px;
  border-radius: 1px;
  background: color-mix(in oklab, var(--paper-ink) 55%, var(--paper));
  rotate: -1.5deg;
}
.k-food-tile i:nth-child(1) {
  top: 26%;
  width: 42%;
  height: 4px;
  background: var(--paper-ink);
}
.k-food-tile i:nth-child(2) {
  top: 50%;
  width: 54%;
}
.k-food-tile i:nth-child(3) {
  top: 63%;
  width: 54%;
}
.k-food-tile i:nth-child(4) {
  top: 76%;
  width: 54%;
}
.k-food-title {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin: 0;
  font: 500 0.9375rem/1.25 var(--font-sans);
  color: var(--foreground);
}
.k-food-title span + span {
  flex: none;
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--muted-foreground);
}
.k-food-rows {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
}
.k-food-rows > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  font: 400 0.875rem/1.3 var(--font-sans);
}
.k-food-rows dt {
  color: var(--muted-foreground);
}
.k-food-rows dd {
  margin: 0;
  color: var(--foreground);
  font-variant-numeric: tabular-nums;
}
.k-food-portion {
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
}

/* ------------------------------------------------------------------ the day's note, on a tab */

/* The Today screenshot stops above the day's note, so a tab on the phone opens it: the lines Kove
   wrote for that day, which are also what was said earlier in the thread. The tab straddles the
   phone's right edge at about the height the note sits at on the real page. The card grows out of
   the tab and its lines are revealed left to right, as if being written. Beside the phone where
   there is room, over its lower half where there is not. With no script the tab is gone and the
   note simply sits under the phone. */
.day-shot {
  position: relative;
  width: fit-content;
  max-width: 100%;
}
.note-tab {
  position: absolute;
  z-index: 2;
  right: 0;
  bottom: 19%;
  translate: 42% 0;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 2.5rem;
  padding: 0 0.95rem;
  border-radius: 99px;
  border: 1px solid color-mix(in oklab, var(--primary) 38%, var(--border));
  background: var(--panel);
  color: var(--foreground);
  font: 500 0.8125rem/1 var(--font-sans);
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.35), 0 12px 26px -12px rgb(0 0 0 / 0.8);
  transition: background-color 150ms var(--ease-out), border-color 150ms var(--ease-out),
    scale 150ms var(--ease-out);
}
.note-tab .ico {
  width: 0.95rem;
  height: 0.95rem;
  flex: none;
  color: var(--primary);
}
.note-tab:hover {
  background: var(--accent);
}
.note-tab:active {
  scale: 0.97;
}
.note-tab[aria-expanded="true"] {
  border-color: var(--primary);
  background: color-mix(in oklab, var(--primary) 12%, var(--panel));
}
.day-note {
  width: min(20rem, 100%);
  margin-top: 1rem;
  padding: 0.875rem 1rem 1rem;
  border-radius: 0.875rem;
  border: 1px solid var(--border);
  background: var(--panel);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3), 0 22px 44px -22px rgb(0 0 0 / 0.85);
}
.day-note-head {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.6rem;
  font: 500 0.75rem/1.3 var(--font-sans);
  color: var(--muted-foreground);
}
.day-note-head .ico {
  width: 0.85rem;
  height: 0.85rem;
  flex: none;
  color: color-mix(in oklab, var(--primary) 70%, transparent);
}
.day-note .nl {
  margin: 0;
  font: 400 0.9375rem/1.55 var(--font-sans);
  color: var(--foreground);
  text-wrap: pretty;
}
.day-note .nl + .nl {
  margin-top: 0.4rem;
}
/* A phone has no room beside the phone, so the tab sits on the screen, over the empty right end
   of the "Open Training" row, instead of straddling the frame (at 320px in Italian that ran 20px
   off the page). */
@media (max-width: 34rem) {
  .note-tab {
    right: 7%;
    translate: 0 0;
    min-height: 2.25rem;
    padding: 0 0.75rem;
    gap: 0.35rem;
    font-size: 0.75rem;
  }
  .note-tab .ico {
    width: 0.85rem;
    height: 0.85rem;
  }
}
html:not(.js) .note-tab {
  display: none;
}
.js .day-note {
  position: absolute;
  z-index: 3;
  display: none;
  margin: 0;
  left: 6%;
  right: 6%;
  width: auto;
  bottom: calc(19% + 3.25rem);
  transform-origin: 85% 100%;
}
.js .day-shot.open .day-note {
  display: block;
}
@media (min-width: 52rem) {
  .js .day-note {
    left: calc(100% + 1.5rem);
    right: auto;
    width: 19rem;
    transform-origin: 0 100%;
  }
}
@media (prefers-reduced-motion: no-preference) {
  .js .day-shot.in .note-tab {
    animation: tab-out 460ms var(--ease-out) 650ms both;
  }
  .js .day-shot.open .day-note {
    animation: note-in 220ms var(--ease-out) both;
  }
  .js .day-shot.open .nl {
    animation: note-write 460ms var(--ease-out) both;
  }
  .js .day-shot.open .nl:nth-child(2) {
    animation-delay: 110ms;
  }
  .js .day-shot.open .nl:nth-child(3) {
    animation-delay: 290ms;
  }
  .js .day-shot.open .nl:nth-child(4) {
    animation-delay: 470ms;
  }
}
@keyframes tab-out {
  from {
    opacity: 0;
    scale: 0.92;
  }
}
@keyframes note-in {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.97);
  }
}
@keyframes note-write {
  from {
    opacity: 0.2;
    clip-path: inset(0 100% 0 0);
  }
  to {
    opacity: 1;
    clip-path: inset(0 0 0 0);
  }
}

/* ------------------------------------------------------------------ the phone, around a REAL screenshot */

/* A device, drawn, around a whole-screen screenshot (430 x 932 points, the app shot with an iPhone's own
   safe areas, web/scripts/shoot-app.mjs). The screenshot is the app's pixels only: the frame adds what
   the PHONE draws over an installed app and nothing else, which is the status bar, the island and the
   home indicator. Everything inside the screen is sized in container units off the screen's own width,
   so one --w scales the whole device. */
.device {
  --w: 18rem;
  position: relative;
  flex: none;
  width: var(--w);
  padding: calc(var(--w) * 0.028);
  border-radius: calc(var(--w) * 0.163);
  background: linear-gradient(152deg, #62675f 0%, #30332f 14%, #151715 46%, #202320 78%, #565a54 100%);
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.07),
    inset 0 0 0 calc(var(--w) * 0.004) rgb(255 255 255 / 0.24),
    inset 0 0 0 calc(var(--w) * 0.014) #070807,
    0 44px 80px -44px rgb(0 0 0 / 0.9),
    0 14px 30px -16px rgb(0 0 0 / 0.6);
}
/* The side buttons: the action button and the two volume keys on the left, the side key on the right.
   One gradient per edge, so three keys cost one pseudo-element. */
.device::before,
.device::after {
  content: "";
  position: absolute;
  width: calc(var(--w) * 0.011);
}
.device::before {
  left: calc(var(--w) * -0.009);
  top: 17%;
  height: 27%;
  border-radius: 2px 0 0 2px;
  background: linear-gradient(
    to bottom,
    #3c403c 0 11%,
    transparent 11% 25%,
    #3c403c 25% 57%,
    transparent 57% 66%,
    #3c403c 66% 100%
  );
}
.device::after {
  right: calc(var(--w) * -0.009);
  top: 27%;
  height: 12%;
  border-radius: 0 2px 2px 0;
  background: #3c403c;
}
.device-screen {
  position: relative;
  container-type: inline-size;
  overflow: hidden;
  border-radius: calc(var(--w) * 0.137);
  background: var(--background);
}
.device-screen > img:first-child {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 430 / 932;
}
/* the island */
.device-screen::before {
  content: "";
  position: absolute;
  z-index: 2;
  top: 2.6cqw;
  left: 50%;
  width: 29cqw;
  height: 8.6cqw;
  translate: -50% 0;
  border-radius: 99px;
  background: #000;
}
/* the home indicator */
.device-screen::after {
  content: "";
  position: absolute;
  z-index: 2;
  bottom: 1.9cqw;
  left: 50%;
  width: 32cqw;
  height: 1.15cqw;
  translate: -50% 0;
  border-radius: 99px;
  background: rgb(255 255 255 / 0.82);
}
.device-status {
  position: absolute;
  z-index: 1;
  inset: 0 0 auto;
  height: 13.8cqw;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4cqw 7.6cqw 0 11.6cqw;
  pointer-events: none;
}
.device-time {
  font: 600 3.95cqw/1 -apple-system, "SF Pro Text", system-ui, sans-serif;
  letter-spacing: -0.01em;
  color: #fff;
}
.device-icons {
  width: 18cqw;
  height: auto;
}

/* A desktop screenshot sits in a browser window, the one on-screen chrome a reader expects around a
   web app on a laptop. */
.window {
  width: min(100%, 42rem);
  border-radius: 0.75rem;
  overflow: hidden;
  border: 1px solid #2f332f;
  background: #141614;
  box-shadow: 0 40px 80px -44px rgb(0 0 0 / 0.9), 0 14px 30px -16px rgb(0 0 0 / 0.55);
}
.window-bar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.75rem;
  height: 2.1rem;
  padding: 0 0.8rem;
  background: #1b1d1b;
  border-bottom: 1px solid #2a2d2a;
}
.window-dots {
  display: flex;
  gap: 0.4rem;
}
.window-dots i {
  width: 0.62rem;
  height: 0.62rem;
  border-radius: 50%;
  background: #3a3e3a;
}
.window-dots i:nth-child(1) {
  background: #ec6a5e;
}
.window-dots i:nth-child(2) {
  background: #f4bf4f;
}
.window-dots i:nth-child(3) {
  background: #61c554;
}
.window-url {
  justify-self: center;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0.2rem 0.9rem;
  border-radius: 0.4rem;
  background: #111311;
  font: 500 0.6875rem/1.2 var(--font-sans);
  color: var(--muted-foreground);
}
.window-bar::after {
  content: "";
  width: 2.6rem;
}
.window > img {
  display: block;
  width: 100%;
  height: auto;
}
.shot-row {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  flex-wrap: wrap;
}
/* ------------------------------------------------------------------ the app's own chat objects */

.k-bubble {
  background: color-mix(in oklab, var(--primary) 12%, var(--background));
  border: 1px solid color-mix(in oklab, var(--primary) 15%, transparent);
  border-radius: 1rem 1rem 0.375rem 1rem;
  padding: 0.625rem 1rem;
  color: var(--foreground);
  font: 400 0.9375rem/1.6 var(--font-sans);
  max-width: min(85%, 26rem);
  margin: 0 0 0 auto;
  width: fit-content;
}
.k-reply {
  font: 400 0.9375rem/1.65 var(--font-sans);
  color: var(--foreground);
  max-width: 34rem;
  margin: 0;
}
.k-reply b {
  font-weight: 600;
}
.k-receipt {
  position: relative;
  width: 100%;
  max-width: 28rem;
  border-radius: 0.75rem;
  padding: 0.75rem;
  border: 1px solid color-mix(in oklab, var(--primary) 30%, transparent);
  background: color-mix(in oklab, var(--primary) 5%, var(--background));
  box-shadow: var(--shadow-resting);
}
.k-receipt-head {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.5rem;
  color: var(--primary);
  font: 500 0.875rem/1 var(--font-sans);
}
/* The receipt's "i", as the app draws it: a muted glyph beside "Logged" that opens the meal's
   breakdown. It exists only once scripts run, since the card it opens needs them. The hit area is
   grown with slop rather than padding, so the header keeps its height. */
.k-info {
  display: none;
  position: relative;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: color-mix(in oklab, var(--muted-foreground) 70%, transparent);
  border-radius: 99px;
  cursor: pointer;
  transition: color 150ms var(--ease-out);
}
.js .k-info {
  display: inline-flex;
}
.k-info::after {
  content: "";
  position: absolute;
  inset: -0.625rem;
}
.k-info:hover,
.k-info[aria-expanded="true"] {
  color: var(--foreground);
}
.k-info .ico {
  width: 0.875rem;
  height: 0.875rem;
}
.k-pop {
  display: none;
  position: absolute;
  z-index: 5;
  top: 2.25rem;
  left: 0.75rem;
  width: min(20rem, calc(100% - 1.5rem));
  padding: 0.5rem 0.625rem;
  border-radius: 0.5rem;
  border: 1px solid var(--border);
  background: var(--panel);
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3), 0 18px 36px -18px rgb(0 0 0 / 0.85);
  font: 400 0.75rem/1.45 var(--font-sans);
  color: var(--foreground);
  transform-origin: top left;
}
.k-pop.open {
  display: block;
  animation: pop-in 140ms var(--ease-out);
}
@keyframes pop-in {
  from {
    opacity: 0;
    transform: scale(0.97) translateY(-2px);
  }
}
.k-pop-label {
  margin: 0 0 0.375rem;
  color: var(--muted-foreground);
}
.k-pop-gap {
  margin-top: 0.625rem;
  margin-bottom: 0.25rem;
}
.k-foods {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.k-foods .r {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0;
}
.k-foods .nm {
  display: flex;
  gap: 0.25rem;
  flex: 1;
  min-width: 0;
}
.k-foods .nm > span:first-child {
  white-space: nowrap;
}
.k-foods .amt {
  color: var(--muted-foreground);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.k-foods .kc,
.k-pop .mac {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.k-foods .kc {
  flex-shrink: 0;
}
.k-pop .mac {
  margin: 0;
  color: var(--muted-foreground);
}
.k-pop > .mac {
  color: var(--foreground);
}
.k-date {
  margin-left: auto;
  color: var(--muted-foreground);
  font: 400 0.75rem/1 var(--font-mono);
  display: inline-flex;
  gap: 0.25rem;
  align-items: center;
}
.k-date .ico {
  width: 0.75rem;
  height: 0.75rem;
}
.k-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}
.k-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 100%;
  background: color-mix(in oklab, var(--background) 60%, transparent);
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  padding: 0.25rem 0.5rem;
  font: 400 0.75rem/1.4 var(--font-mono);
  color: var(--muted-foreground);
}
.k-pill .v {
  color: var(--foreground);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}
.k-marker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  font: 400 0.875rem/1.4 var(--font-sans);
  color: var(--muted-foreground);
  margin: 0;
}
.k-marker .lnk {
  color: var(--primary);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
}
.k-marker .lit {
  color: var(--primary);
}
.k-marker .lnk .ico {
  width: 0.8rem;
  height: 0.8rem;
}
.k-widget {
  width: 100%;
  max-width: 28rem;
  border-radius: 0.75rem;
  border: 1px solid var(--border);
  background: var(--card);
  padding: 0.875rem;
  box-shadow: var(--shadow-resting);
}
.k-widget-head {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font: 500 0.875rem/1 var(--font-sans);
  color: var(--foreground);
  margin-bottom: 0.6rem;
}
.k-widget-head span + span {
  color: var(--muted-foreground);
  font-weight: 400;
}
.k-offer {
  width: 100%;
  max-width: 28rem;
  border-radius: 0.75rem;
  padding: 0.75rem;
  border: 1px dashed var(--input);
}
.k-offer-head {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin: 0 0 0.5rem;
  color: var(--primary);
  font: 500 0.875rem/1 var(--font-sans);
}
.k-offer .actions {
  margin: 0;
  gap: 0.5rem;
}
/* The offer's two states, the app's own (SuggestionChip in web/src/Chat.tsx). Pending, the pill is
   selected and tinted and Add sits under it with the line saying nothing is lost. Once added, the
   header says so, the pill keeps a bare check, the button row goes, and one line says where the
   field went. The field name there is plain text, as the app draws it with no link to follow. */
.k-offer .k-pill {
  border-color: color-mix(in oklab, var(--primary) 40%, transparent);
  background: color-mix(in oklab, var(--primary) 10%, transparent);
}
.k-offer-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.625rem;
  margin-top: 0.625rem;
}
.k-offer-note {
  font: 400 0.75rem/1.4 var(--font-sans);
  color: var(--muted-foreground);
}
.k-added {
  display: none;
  align-items: center;
  gap: 0.375rem;
  margin: 0.625rem 0 0;
  font: 400 0.75rem/1.4 var(--font-sans);
  color: var(--muted-foreground);
  outline: none;
}
.k-added .ico {
  width: 0.875rem;
  height: 0.875rem;
  flex: none;
  color: color-mix(in oklab, var(--primary) 70%, transparent);
}
.k-added .nm {
  color: var(--foreground);
  font-weight: 500;
}
.k-offer .when-added,
.k-offer.added .when-open,
.k-offer.added .k-offer-foot {
  display: none;
}
.k-offer.added .when-added {
  display: inline;
}
.k-offer.added .k-added {
  display: flex;
}
/* What accepting buys, said once the field exists: it fills itself in from here on. Indented to the
   text of the line above rather than its icon. */
.k-auto {
  display: none;
  margin: 0.25rem 0 0;
  padding-left: 1.25rem;
  font: 400 0.75rem/1.45 var(--font-sans);
  color: var(--muted-foreground);
}
.k-offer.added .k-auto {
  display: block;
}
.k-offer.added .k-check {
  background: transparent;
  border-color: transparent;
  color: var(--primary);
}
.k-check {
  width: 1rem;
  height: 1rem;
  border-radius: 0.25rem;
  border: 1px solid var(--primary);
  background: var(--primary);
  display: inline-grid;
  place-items: center;
  color: var(--primary-foreground);
  flex: none;
}
.k-check .ico {
  width: 0.7rem;
  height: 0.7rem;
}

/* ================================================================== THE HOME: one conversation */

/* The header is wider than the thread, so the Italian nav and call to action never share 46rem. */
.home .topbar > .sheet {
  max-width: calc(62rem + 2 * var(--gutter));
}

.home .thread {
  max-width: calc(var(--frame) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 1.5rem var(--gutter) 3rem;
}
.day-mark {
  text-align: center;
  font: 500 0.75rem/1 var(--font-sans);
  color: var(--muted-foreground);
  margin: 0.5rem 0 1.5rem;
}
.ex {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  margin: 0 0 2.75rem;
}
.ex .k {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  align-items: flex-start;
}
.ex-last {
  margin-bottom: 0;
}
/* Text in a thread sits on its own layer. The device frames are positioned, and a positioned box
   paints above ordinary text that comes after it, so a phone's long drop shadow (80px of blur under
   the frame) landed ON the paragraph below it and dimmed half a line. Positioning the text too puts
   it back in document order, above the shadow. */
.ex > p,
.ex .k > p {
  position: relative;
}
.hero-reply {
  font: 600 clamp(2.5rem, 7.2vw, 4.75rem)/0.98 var(--font-display);
  letter-spacing: -0.035em;
  margin: 0.25rem 0 0;
  max-width: 12ch;
  text-wrap: balance;
}
.hero-reply em {
  font-style: normal;
  color: var(--primary);
}
.hero-sub {
  font-size: 1.0625rem;
  line-height: 1.55;
  color: color-mix(in oklab, var(--foreground) 82%, var(--background));
  max-width: 30rem;
  margin: 0;
}
.hero-price {
  font: 400 0.8125rem/1.5 var(--font-mono);
  color: var(--muted-foreground);
  margin: 0;
}
.status {
  display: none;
  align-items: center;
  gap: 0.5rem;
  color: var(--muted-foreground);
  font-size: 0.875rem;
  margin: 0;
}
.dots {
  display: inline-flex;
  gap: 3px;
}
.dots i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  animation: dot 1s var(--ease-out) infinite;
}
.dots i:nth-child(2) {
  animation-delay: 0.15s;
}
.dots i:nth-child(3) {
  animation-delay: 0.3s;
}
@keyframes dot {
  0%,
  100% {
    opacity: 0.25;
    transform: translateY(0);
  }
  40% {
    opacity: 1;
    transform: translateY(-2px);
  }
}
.note-s {
  font: 400 0.75rem/1.5 var(--font-sans);
  color: var(--muted-foreground);
  margin: -0.25rem 0 0;
}
.home .device {
  --w: 18rem;
}

/* one-tap shortcuts, the app's quick-add pill */
.quick {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.qa {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  height: 2.25rem;
  padding: 0 0.85rem;
  border-radius: 99px;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--foreground);
  font: 500 0.8125rem/1 var(--font-sans);
  cursor: pointer;
  transition: background-color 150ms var(--ease-out), transform 150ms var(--ease-out),
    border-color 150ms var(--ease-out);
}
.qa:hover {
  background: var(--accent);
}
.qa:active {
  transform: scale(0.96);
}
.qa .em {
  font-size: 0.95rem;
}
.qa .plus {
  color: var(--primary);
  font: 500 0.75rem/1 var(--font-mono);
}
/* A tap never changes the pill's size: it lights for a moment, and the confirmation rises off it and
   dissolves above, where nothing else lives. Several taps in a row each send their own. */
.qa {
  position: relative;
}
.qa.done {
  border-color: color-mix(in oklab, var(--primary) 45%, transparent);
  background: color-mix(in oklab, var(--primary) 8%, var(--card));
}
.qa-float {
  position: absolute;
  left: 50%;
  bottom: 100%;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.2rem 0.5rem;
  border-radius: 99px;
  background: color-mix(in oklab, var(--primary) 14%, var(--panel));
  border: 1px solid color-mix(in oklab, var(--primary) 35%, transparent);
  color: var(--primary);
  font: 500 0.75rem/1 var(--font-mono);
  white-space: nowrap;
  pointer-events: none;
  transform: translateX(-50%);
  opacity: 0;
}
.qa-float .ico {
  width: 0.75rem;
  height: 0.75rem;
}
.sr-live {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* the pieces: things people track, as paper tickets, on How it works. Each states how it counts,
   and a tap moves it into "Your fields" (how.js); a tap there takes it back. */
.pieces {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 1rem;
  background: var(--card);
  box-shadow: var(--shadow-resting);
  padding: 1.1rem;
}
.pile {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 0.6rem;
  padding: 0.25rem 0.1rem 1rem;
}
.stub {
  appearance: none;
  border: 0;
  margin: 0;
  cursor: pointer;
  background: var(--paper);
  color: var(--paper-ink);
  font: 600 0.875rem/1 var(--font-mono);
  text-align: left;
  padding: 0.7rem 0.95rem 0.7rem 1.25rem;
  transition: rotate 300ms var(--ease-out), translate 300ms var(--ease-out), opacity 300ms var(--ease-out),
    filter 300ms var(--ease-out);
  -webkit-mask: radial-gradient(circle at 0 50%, #0000 0.38rem, #000 0.4rem);
  mask: radial-gradient(circle at 0 50%, #0000 0.38rem, #000 0.4rem);
}
.stub:nth-child(8n + 1) { rotate: -2deg; }
.stub:nth-child(8n + 2) { rotate: 1.5deg; }
.stub:nth-child(8n + 3) { rotate: -1deg; }
.stub:nth-child(8n + 4) { rotate: 2deg; }
.stub:nth-child(8n + 5) { rotate: -1.5deg; }
.stub:nth-child(8n + 6) { rotate: 1deg; }
.stub:nth-child(8n + 7) { rotate: -2.5deg; }
.stub:nth-child(8n + 8) { rotate: 1.5deg; }
.stub small {
  display: block;
  font: 500 0.6875rem/1 var(--font-mono);
  color: #676d67;
  margin-top: 0.4rem;
}
.stub:hover {
  rotate: 0deg;
  translate: 0 -3px;
}
.stub.used {
  opacity: 0.22;
  filter: grayscale(1);
  pointer-events: none;
  rotate: 0deg;
}
.tray-h {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-top: 1px solid var(--border);
  padding-top: 0.9rem;
  margin: 0 0 0.6rem;
  font: 500 0.8125rem/1 var(--font-sans);
  color: var(--muted-foreground);
}
.tray-h b {
  color: var(--foreground);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.tray {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}
.tpill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  padding: 0.3rem 0.55rem;
  background: color-mix(in oklab, var(--background) 60%, transparent);
  font: 400 0.75rem/1.4 var(--font-mono);
  color: var(--muted-foreground);
}
.tpill .g {
  opacity: 0.8;
}
button.tpill {
  color: var(--foreground);
  border-color: color-mix(in oklab, var(--primary) 40%, transparent);
  cursor: pointer;
}
button.tpill .g {
  color: var(--primary);
  opacity: 1;
}
button.tpill:hover {
  background: var(--accent);
}
.page .pieces {
  box-shadow: var(--shadow-light);
}
.flyer {
  position: fixed;
  z-index: 60;
  pointer-events: none;
  margin: 0;
  rotate: 0deg;
}
.legend {
  font: 400 0.75rem/1.5 var(--font-sans);
  color: var(--muted-foreground);
  margin: 0.9rem 0 0;
}

/* a week drawn in one ink */
.week svg {
  width: 100%;
  height: 7rem;
  overflow: visible;
}
.week .bar {
  fill: color-mix(in oklab, var(--foreground) 62%, var(--card));
}
.week .gap {
  fill: none;
  stroke: var(--border);
  stroke-dasharray: 3 3;
}
.week .tgt {
  stroke: var(--input);
  stroke-dasharray: 4 4;
}
.week-row {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  font: 400 0.6875rem/1.3 var(--font-mono);
  color: var(--muted-foreground);
  margin-top: 0.4rem;
}
.week-row.days {
  font-family: var(--font-sans);
  font-weight: 500;
  margin-top: 0.15rem;
}

/* the reading card chart */
.chart {
  position: relative;
}
.chart svg {
  width: 100%;
  height: 9rem;
  overflow: visible;
}
.chart .line {
  fill: none;
  stroke: var(--primary);
  stroke-width: 2;
}
.chart .area {
  fill: url(#sleepfill);
}
.chart .rule {
  stroke: var(--border);
}
.chart .rule.top {
  stroke-dasharray: 2 4;
}
.chart .guide {
  stroke: var(--muted-foreground);
  opacity: 0;
}
.chart .tip {
  position: absolute;
  top: -0.25rem;
  translate: -50% -100%;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  padding: 0.25rem 0.45rem;
  font: 500 0.75rem/1 var(--font-sans);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 120ms;
  pointer-events: none;
}
.chart.hovering .tip {
  opacity: 1;
}
.chart.hovering .guide {
  opacity: 0.6;
}
.axis {
  display: flex;
  justify-content: space-between;
  font: 400 0.6875rem/1 var(--font-sans);
  color: var(--muted-foreground);
  margin-top: 0.4rem;
}

/* the price: the per-day figure leads, the yearly one right under it */
.price {
  width: 100%;
  max-width: 28rem;
  border: 1px solid var(--border);
  border-radius: 1rem;
  background: var(--card);
  box-shadow: var(--shadow-resting);
  overflow: hidden;
}
/* The trial leads the card: it is the first thing a reader has to decide about, so it is stated
   before any figure, in a tinted band (the accent as a tint, never a second solid lamp beside the
   close band's). */
.price-trial {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  padding: 0.7rem 1.2rem;
  border-bottom: 1px solid color-mix(in oklab, var(--primary) 22%, transparent);
  background: color-mix(in oklab, var(--primary) 10%, var(--card));
  color: color-mix(in oklab, var(--foreground) 85%, var(--background));
  font-size: 0.9375rem;
  line-height: 1.4;
}
.price-trial > span {
  min-width: 0;
}
.price-trial b {
  display: block;
  color: var(--primary);
  font-weight: 600;
}
.price-trial .ico {
  flex: none;
  width: 1rem;
  height: 1rem;
  color: var(--primary);
}
/* One column, in reading order: the tag, the daily figure, then the same price as a year with its
   condition under it. Side by side, "€0.08" and "€29 a year" read as two competing offers, and the
   squeeze broke "a day" and the condition onto ragged lines. */
.price-top {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 1.1rem 1.2rem 1.1rem;
}
.price-tag {
  display: inline-block;
  font: 600 0.75rem/1 var(--font-sans);
  color: var(--primary-foreground);
  background: var(--primary);
  padding: 0.35rem 0.5rem;
  border-radius: 0.3rem;
  margin: 0 0 0.7rem;
}
.fig {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0;
  font: 600 3.4rem/0.9 var(--font-display);
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}
.fig small {
  font: 500 1rem/1 var(--font-sans);
  letter-spacing: 0;
  color: var(--muted-foreground);
  white-space: nowrap;
}
.price-yr {
  font-size: 0.875rem;
  line-height: 1.45;
  margin: 0.9rem 0 0;
  color: color-mix(in oklab, var(--foreground) 72%, var(--background));
  text-wrap: pretty;
}
.price-yr b {
  display: block;
  margin-bottom: 0.1rem;
  font: 600 1.125rem/1.25 var(--font-display);
  color: var(--foreground);
}
.price-rows {
  margin: 0;
}
.price-rows div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 1.2rem;
  border-top: 1px solid var(--border);
  font-size: 0.9375rem;
}
.price-rows dt {
  color: color-mix(in oklab, var(--foreground) 78%, var(--background));
}
.price-rows dd {
  margin: 0;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* the person who builds it: the quote on the reply's own left edge, the byline under it */
.founder {
  display: grid;
  gap: 0.85rem;
  max-width: 32rem;
  margin: 0.25rem 0 0;
}
.founder blockquote {
  margin: 0;
  font-size: 1.0625rem;
  line-height: 1.55;
  color: color-mix(in oklab, var(--foreground) 90%, var(--background));
}
.founder blockquote p {
  margin: 0;
}
.founder blockquote p::before {
  content: "\201C";
}
.founder blockquote p::after {
  content: "\201D";
}
.founder figcaption {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}
.face {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  flex: none;
}

.more-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.25rem;
  margin: 0;
  font-size: 0.8125rem;
}
.more-links a {
  color: var(--foreground);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.more-links a:hover {
  color: var(--primary);
}

/* the quick-reply dock */
.dock {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  padding: 0.75rem var(--gutter) calc(0.75rem + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--background) 62%, transparent);
  transition: opacity 250ms var(--ease-out), translate 300ms var(--ease-out);
}
.dock.away {
  opacity: 0;
  translate: 0 1rem;
  pointer-events: none;
}
.dock-in {
  max-width: var(--frame);
  margin: 0 auto;
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}
.qr {
  height: 2.5rem;
  padding: 0 1rem;
  border-radius: 99px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font: 500 0.875rem/1 var(--font-sans);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 160ms var(--ease-out), transform 160ms var(--ease-out);
}
.qr:hover {
  background: var(--accent);
}
.qr:active {
  transform: scale(0.97);
}
.qr.go {
  background: var(--primary);
  color: var(--primary-foreground);
  border-color: var(--primary);
  font-weight: 600;
}
.qr.go:hover {
  background: color-mix(in oklab, var(--primary) 88%, white);
}
.home .footer {
  padding-bottom: 7rem;
}

/* The conversation arrives as you reach it. Hidden only once boot.js has marked the document, and
   a failsafe brings everything in after four seconds if main.js never runs, so no reader can be
   left looking at a blank thread. The first exchange is never hidden: it is the headline. */
.js .ex.stage > .k-photo,
.js .ex.stage > .k-bubble,
.js .ex.stage .k > * {
  opacity: 0;
  transform: translateY(8px);
}
/* The failsafe is for a main.js that never ran. Once the staging is live (main.js sets
   .stage-live), an exchange waits to be reached however long that takes: a failsafe firing
   under a live stage revealed every answer after four seconds, and reaching one then still
   played its status line over an answer already on screen. */
.js:not(.stage-live) .ex.stage > .k-photo,
.js:not(.stage-live) .ex.stage > .k-bubble,
.js:not(.stage-live) .ex.stage .k > * {
  animation: failsafe 1ms 4s forwards;
}
.js .ex.stage > .k-photo.in,
.js .ex.stage > .k-bubble.in,
.js .ex.stage .k > .in {
  opacity: 1;
  transform: none;
  animation: none;
  transition: opacity 320ms var(--ease-out), transform 420ms var(--ease-out);
}
/* The status line takes NO room: its negative margin cancels its own line and the gap, so it sits
   over the top of the (still invisible) answer and nothing below it moves when it comes or goes.
   It fades rather than blinking in and out, and it never shows unless main.js plays it. */
.js .ex.stage > .status {
  display: inline-flex;
  align-self: flex-start;
  line-height: 1.25rem;
  margin-bottom: calc(-1.25rem - 0.875rem);
  opacity: 0;
  transition: opacity 140ms var(--ease-out);
  pointer-events: none;
}
.js .ex.stage > .status.in {
  opacity: 1;
}
@keyframes failsafe {
  to {
    opacity: 1;
    transform: none;
  }
}

@media (max-width: 34rem) {
  .dock-in {
    justify-content: stretch;
  }
  .qr {
    flex: 1;
    padding: 0 0.6rem;
  }
  .qr.hide-s {
    display: none;
  }
  .home .device {
    --w: min(19rem, 82vw);
  }
  /* The header's button would be the dock's twin on every screen, so on a phone the dock carries
     the action alone and the brand keeps its name. */
  .home .topbar-cta {
    display: none;
  }
  .home .wordmark-text {
    display: inline;
  }
}

/* ================================================================== SECONDARY PAGES: light reading */

body.page {
  background: var(--light-bg);
  color: var(--light-ink);
  --frame: 72rem;
}
.page ::selection {
  background: #c9f7cd;
  color: var(--light-ink);
}
.page main :focus-visible {
  outline-color: var(--light-link);
}
.page .rail {
  display: none;
}
.page .band > .sheet {
  max-width: calc(var(--frame) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.page .band {
  padding: clamp(2.5rem, 6vw, 4.25rem) 0 0;
}
.page .band-hero {
  background: var(--primary);
  color: var(--primary-foreground);
  padding: clamp(2.75rem, 7vw, 5.5rem) 0 clamp(3rem, 7vw, 5.5rem);
}
.page .band-hero + .band {
  padding-top: clamp(3.5rem, 8vw, 6rem);
}
.page h1 {
  font: 700 clamp(2.6rem, 6.4vw, 5.25rem)/0.95 var(--font-display);
  letter-spacing: -0.04em;
  margin: 0 0 1.25rem;
  max-width: 15ch;
  text-wrap: balance;
}
.page .lede {
  font-size: clamp(1.1rem, 1.6vw, 1.3rem);
  line-height: 1.5;
  max-width: 36rem;
  margin: 0;
  color: color-mix(in oklab, var(--primary-foreground) 82%, var(--primary));
}
.page .band-hero .actions,
.page .band-hero .jump {
  margin-top: 1.75rem;
}
.page .band-hero .btn-primary,
.page .band-close .btn-primary {
  background: var(--primary-foreground);
  color: var(--primary);
}
.page .band-hero .btn-primary:hover,
.page .band-close .btn-primary:hover {
  background: #12291a;
}
.page .band-hero .quiet-link,
.page .band-close .quiet-link {
  color: var(--primary-foreground);
}
.jump {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
/* Specific enough to beat the reading pages' link rule (`.page main a:not(.btn):not(.quiet-link)`,
   which comes later in this file): without it that rule painted these pills' words in the
   light-page link green on the lime hero, mid-green words inside near-black borders. */
.page main .band-hero .jump a[href] {
  display: inline-flex;
  align-items: center;
  height: 2.25rem;
  padding: 0 0.9rem;
  border-radius: 99px;
  border: 1.5px solid color-mix(in oklab, var(--primary-foreground) 70%, transparent);
  color: var(--primary-foreground);
  text-decoration: none;
  font: 500 0.875rem/1 var(--font-sans);
  transition: background-color 150ms var(--ease-out);
}
.page main .band-hero .jump a[href]:hover {
  background: color-mix(in oklab, var(--primary-foreground) 10%, transparent);
}
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  margin: 1.5rem 0 0;
}
.quiet-link {
  color: inherit;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  font-size: 0.9375rem;
}

/* A section: its title in a sticky column on the left, the answer on the right. On a phone the two
   stack. A .pair or a .wide child spans both columns. */
.page .band:not(.band-hero):not(.band-close) .cells {
  display: grid;
  grid-template-columns: minmax(0, 16rem) minmax(0, 44rem);
  column-gap: clamp(2rem, 6vw, 5.5rem);
  align-items: start;
  border-top: 1px solid var(--light-line);
  padding-top: clamp(2.5rem, 6vw, 4rem);
}
/* The accuracy page's hero holds its proof: the copy on the left, a scoreboard of the four figures on the right
   (under the copy on a phone). Dark tiles on the lime hero, so the numbers are the loudest thing on screen. */
.page .band-hero .hero-split {
  display: grid;
  gap: 2.5rem;
}
@media (min-width: 60rem) {
  .page .band-hero .hero-split {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    align-items: center;
    column-gap: clamp(2rem, 5vw, 4.5rem);
  }
}
.scoreboard {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}
.score-tile {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  background: var(--primary-foreground);
  color: var(--primary);
  border-radius: 0.875rem;
  padding: 1rem 1.1rem 1.1rem;
}
.score-v {
  font: 700 clamp(2rem, 4.2vw, 2.75rem)/1 var(--font-display);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.score-k {
  font: 500 0.875rem/1.3 var(--font-sans);
  color: color-mix(in oklab, var(--primary) 88%, var(--primary-foreground));
}
.score-s {
  font: 400 0.8125rem/1.3 var(--font-sans);
  color: color-mix(in oklab, var(--primary) 62%, var(--primary-foreground));
}
/* A photographed plate on the accuracy page: the photo Kove was shown, beside its heaviest ingredients. */
.plate-cell {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.page .figtable-plates th,
.page .figtable-plates td {
  vertical-align: middle;
}
.plate-thumb {
  flex: none;
  width: 3.5rem;
  height: 3.5rem;
  object-fit: cover;
  border-radius: 0.5rem;
  background: var(--light-line);
}

/* Model alone against Kove: Kove's column carries the weight, since it is the figure the reader gets. */
.page .figtable-vs td:last-child .figv {
  font-weight: 600;
  color: var(--light-ink);
}

/* A callout on a reading page: a short note about the page itself (the accuracy page's "what this
   is"), in the light tint so it reads as an aside and not as one more section. */
.page .callout {
  max-width: 44rem;
  background: var(--light-tint);
  border: 1px solid var(--light-line);
  border-radius: 0.875rem;
  padding: 1.1rem 1.25rem;
}
.page .callout-h {
  margin: 0 0 0.35rem;
  font: 600 1rem/1.3 var(--font-display);
  color: var(--light-ink);
}
.page .callout p:not(.callout-h) {
  margin: 0;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--light-body);
}
.page .callout p:not(.callout-h) + p {
  margin-top: 0.6rem;
}
.page .callout p.caption {
  font-size: 0.8125rem;
  color: var(--light-faint);
}

/* The same specificity as the rule above, so source order lets the first section under the hero
   skip its hairline: the lime edge already separates them. */
.page .band-hero + .band:not(.band-close) .cells {
  border-top: 0;
  padding-top: 0;
}
.page .band:not(.band-hero):not(.band-close) .cells > * {
  grid-column: 2;
}
.page .band:not(.band-hero):not(.band-close) .cells > h2:first-child {
  grid-column: 1;
  grid-row: 1 / span 60;
  position: sticky;
  top: calc(var(--header-h) + 1.5rem);
}
.page .band:not(.band-hero):not(.band-close) .cells > .pair,
.page .band:not(.band-hero):not(.band-close) .cells > .wide {
  grid-column: 1 / -1;
}
.page .cells > .wide {
  margin-top: 0.75rem;
}
.page h2 {
  font: 600 clamp(1.55rem, 2.8vw, 2.2rem)/1.08 var(--font-display);
  letter-spacing: -0.03em;
  margin: 0 0 1.25rem;
  text-wrap: balance;
}
.page h3.sub {
  font: 600 1.15rem/1.3 var(--font-display);
  letter-spacing: -0.01em;
  margin: 2rem 0 0.5rem;
  color: var(--light-ink);
}
.page .cells > h3.sub:nth-child(2),
.page .pair-text > h3.sub:first-child {
  margin-top: 0;
}
.page p.body {
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--light-body);
  margin: 0 0 1rem;
  max-width: 42rem;
}
.page main a:not(.btn):not(.quiet-link) {
  color: var(--light-link);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.page main .cells > .quiet-link,
.page main .faq-more,
.page main p > .quiet-link {
  color: var(--light-link);
}
/* On the lime bands every link is ink. The light-page link green above is for the white reading
   canvas; on lime it read as a paler word inside an otherwise ink line (the close's "How it is
   handled", the privacy and terms cross-links). */
.page main :is(.band-hero, .band-close) a[href]:not(.btn) {
  color: var(--primary-foreground);
}
.caption {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--light-faint);
  margin: 0.75rem 0 0;
}
.page .band-close .caption {
  color: color-mix(in oklab, var(--primary-foreground) 75%, var(--primary));
}
.page .band-close .caption a,
.band-lime .terms a {
  color: inherit;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
/* "Try this": example messages on the guide, drawn as the app's own user bubble (a lime tint, the
   corner nearest the sender tighter) adapted to the light reading canvas. They are examples to
   read, not controls, so nothing about them looks tappable. */
/* The guide's skim path: one or two phrases per paragraph carry the point, so the page reads from
   the bold alone. Ink on the body's softer grey, one weight step, nothing else. */
.page .body b,
.page .plain-list b {
  font-weight: 600;
  color: var(--light-ink);
}
.try {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 1.5rem 0 0;
}
.try-h {
  margin: 0 0 0.125rem;
  font: 600 0.8125rem/1.3 var(--font-sans);
  color: var(--light-faint);
}
.try-msg {
  max-width: 26rem;
  margin: 0;
  padding: 0.6rem 0.9rem;
  border-radius: 1rem 1rem 1rem 0.3rem;
  background: color-mix(in oklab, var(--primary) 30%, var(--light-bg));
  border: 1px solid color-mix(in oklab, var(--primary) 55%, var(--light-bg));
  color: var(--light-ink);
  font-size: 0.9375rem;
  line-height: 1.45;
}
.plain-list {
  margin: 0 0 1.25rem;
  padding: 0;
  list-style: none;
  counter-reset: item;
  max-width: 42rem;
}
.plain-list li {
  position: relative;
  padding: 0 0 0 1.75rem;
  margin: 0 0 0.6rem;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--light-body);
}
ul.plain-list li::before {
  content: "";
  position: absolute;
  left: 0.35rem;
  top: 0.62em;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: #3fbf4c;
}
ol.plain-list li {
  counter-increment: item;
}
ol.plain-list li::before {
  content: counter(item);
  position: absolute;
  left: 0;
  top: 0.15em;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background: var(--light-ink);
  color: var(--primary);
  font: 600 0.75rem/1.25rem var(--font-sans);
  text-align: center;
}
.page .quote {
  margin: 0 0 1.25rem;
  max-width: 42rem;
}
.page .quote blockquote {
  margin: 0;
  background: var(--light-card);
  border: 1px solid var(--light-line);
  border-radius: 0.875rem;
  padding: 1.1rem 1.25rem 1.1rem 3rem;
  position: relative;
  box-shadow: var(--shadow-light);
}
.page .quote blockquote::before {
  content: "\201C";
  position: absolute;
  left: 1rem;
  top: 0.55rem;
  font: 700 2.4rem/1 var(--font-display);
  color: #3fbf4c;
}
.page .quote blockquote p {
  margin: 0;
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--light-ink);
}
.page .quote figcaption {
  margin: 0.5rem 0 0 0.25rem;
  font-size: 0.8125rem;
  color: var(--light-faint);
}

/* a text-and-phone pair */
.pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "head plate" "text plate";
  column-gap: clamp(2rem, 6vw, 5rem);
  align-items: start;
}
.pair-head {
  grid-area: head;
}
.pair-text {
  grid-area: text;
}
.pair > .plate {
  grid-area: plate;
  margin: 0;
}
.page .band-hero .pair {
  align-items: center;
}
.plate {
  margin: 1.5rem 0;
}
.plate .shot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}
.plate-phone .device {
  --w: 17rem;
}
.page .device {
  box-shadow:
    inset 0 0 0 calc(var(--w) * 0.004) rgb(255 255 255 / 0.16),
    inset 0 0 0 calc(var(--w) * 0.014) #070807,
    0 40px 70px -38px rgb(15 18 15 / 0.55),
    0 12px 24px -14px rgb(15 18 15 / 0.35);
}
.page .band-hero .device {
  box-shadow:
    inset 0 0 0 calc(var(--w) * 0.004) rgb(255 255 255 / 0.16),
    inset 0 0 0 calc(var(--w) * 0.014) #070807,
    0 40px 70px -36px rgb(7 19 10 / 0.6);
}

/* the app, dark, set on the light page: the Yazio page's static receipt */
.page .thread {
  background: var(--background);
  color: var(--foreground);
  border-radius: 1.25rem;
  padding: 1.25rem;
  max-width: 30rem;
  margin: 0 0 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  box-shadow: var(--shadow-light);
}
.page .thread .said {
  margin: 0 0 0 auto;
  width: fit-content;
  max-width: 85%;
  background: color-mix(in oklab, var(--primary) 12%, var(--background));
  border: 1px solid color-mix(in oklab, var(--primary) 15%, transparent);
  border-radius: 1rem 1rem 0.375rem 1rem;
  padding: 0.625rem 1rem;
  font-size: 0.9375rem;
  line-height: 1.55;
}
.page .receipt {
  border-radius: 0.75rem;
  padding: 0.75rem;
  border: 1px solid color-mix(in oklab, var(--primary) 30%, transparent);
  background: color-mix(in oklab, var(--primary) 5%, var(--background));
}
.page .receipt-head {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-bottom: 0.5rem;
  color: var(--primary);
  font: 500 0.875rem/1 var(--font-sans);
}
.page .receipt-date {
  margin-left: auto;
  color: var(--muted-foreground);
  font: 400 0.75rem/1 var(--font-mono);
}
.page .pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin: 0;
}
.page .pill {
  display: inline-flex;
  gap: 0.375rem;
  align-items: center;
  background: color-mix(in oklab, var(--background) 60%, transparent);
  border: 1px solid var(--border);
  border-radius: 0.375rem;
  padding: 0.25rem 0.5rem;
  font: 400 0.75rem/1.4 var(--font-mono);
  color: var(--muted-foreground);
}
.page .pill dt,
.page .pill dd {
  margin: 0;
}
.page .pill dd {
  color: var(--foreground);
  font-size: 0.875rem;
}

/* the close on a light page */
.page .band-close {
  margin-top: clamp(4rem, 9vw, 7rem);
  padding: clamp(3.5rem, 8vw, 6rem) 0 clamp(4rem, 8vw, 6rem);
}
.page .band-close p.body {
  color: var(--primary-foreground);
  max-width: 36rem;
}
.page .band-close .actions {
  margin-top: 1.5rem;
}

@media (max-width: 52rem) {
  .page .band:not(.band-hero):not(.band-close) .cells {
    grid-template-columns: minmax(0, 1fr);
  }
  .page .band:not(.band-hero):not(.band-close) .cells > *,
  .page .band:not(.band-hero):not(.band-close) .cells > h2:first-child {
    grid-column: 1;
    grid-row: auto;
    position: static;
  }
  .pair {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "head" "plate" "text";
  }
  .pair > .plate {
    margin: 1.5rem 0;
  }
  .plate-phone .device {
    --w: min(17rem, 80vw);
  }
}

/* ================================================================== HOW IT WORKS */

/* The app, dark, inside the light page: the split demo. Words on one side, the record on the
   other, and each phrase crossing the seam to the field it fills. */
.seam {
  display: grid;
  grid-template-columns: 1fr 3rem 1fr;
  background: var(--card);
  color: var(--foreground);
  border-radius: 1.25rem;
  box-shadow: 0 0 0 1px #262a26, 0 30px 60px -34px rgb(15 18 15 / 0.6);
  overflow: hidden;
  min-height: 24rem;
}
.seam-pane {
  padding: 1.4rem 1.5rem 1.5rem;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.seam-h {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font: 500 0.8125rem/1 var(--font-sans);
  color: var(--muted-foreground);
  margin: 0 0 1.1rem;
}
.seam-said {
  font: 500 clamp(1.3rem, 2.3vw, 1.85rem)/1.35 var(--font-sans);
  letter-spacing: -0.015em;
  margin: 0;
  min-height: 5.5em;
}
.seam-said .ph {
  border-radius: 0.2rem;
  transition: color 300ms var(--ease-out), box-shadow 300ms var(--ease-out);
}
.seam-said .ph.lit {
  color: var(--primary);
  box-shadow: inset 0 -2px 0 color-mix(in oklab, var(--primary) 55%, transparent);
}
.caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  background: var(--primary);
  vertical-align: -0.15em;
  margin-left: 1px;
  animation: blink 1s steps(1) infinite;
}
@keyframes blink {
  50% {
    opacity: 0;
  }
}
.seam-band {
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  background: var(--background);
  display: grid;
  place-items: center;
}
.seam-band span {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font: 500 0.75rem/1 var(--font-mono);
  letter-spacing: 0.08em;
  color: var(--muted-foreground);
  transition: color 200ms;
}
.seam-band.pulse span {
  color: var(--primary);
}
.rec {
  display: grid;
  /* The name column keeps a floor, so a long value (the knee's offer) wraps inside its own column
     instead of squeezing the names onto two lines on a small phone. */
  grid-template-columns: minmax(7.5rem, 1fr) minmax(0, auto);
  font-size: 0.9375rem;
  margin: 0;
}
.rec > div {
  display: contents;
}
.rec dt,
.rec dd {
  padding: 0.45rem 0;
  border-top: 1px solid var(--border);
  margin: 0;
}
.rec > div:first-child dt,
.rec > div:first-child dd {
  border-top: 0;
}
.rec dt {
  color: color-mix(in oklab, var(--foreground) 78%, var(--background));
}
.rec dd {
  text-align: right;
  font: 400 0.9375rem/1.45 var(--font-mono);
  color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
  padding-left: 1rem;
  transition: color 250ms, background-color 600ms var(--ease-out);
}
.rec dd.set {
  color: var(--foreground);
}
.rec dd.flash {
  background: color-mix(in oklab, var(--primary) 14%, transparent);
}
.rec dd.offered {
  text-wrap: balance;
  color: var(--primary);
  font-family: var(--font-sans);
  font-size: 0.8125rem;
}
.seam-note {
  margin: 1rem 0 0;
  border-radius: 0.625rem;
  background: var(--background);
  border: 1px solid var(--border);
  padding: 0.75rem 0.875rem;
  font-size: 0.875rem;
  line-height: 1.55;
  color: color-mix(in oklab, var(--foreground) 82%, var(--background));
  min-height: 4.5rem;
}
.seam-note b {
  display: block;
  font: 500 0.75rem/1 var(--font-sans);
  color: var(--muted-foreground);
  margin-bottom: 0.4rem;
}
.seam-note span {
  display: block;
  transition: opacity 400ms var(--ease-out);
}
.js .seam-note span.pending {
  opacity: 0;
}
.fly {
  position: fixed;
  z-index: 50;
  left: 0;
  top: 0;
  pointer-events: none;
  background: color-mix(in oklab, var(--primary) 16%, var(--card));
  border: 1px solid color-mix(in oklab, var(--primary) 45%, transparent);
  color: var(--primary);
  font: 500 0.8125rem/1 var(--font-sans);
  padding: 0.4rem 0.6rem;
  border-radius: 99px;
  white-space: nowrap;
}
.tries {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 1rem 0 0;
}
.tries .lbl {
  font-size: 0.8125rem;
  color: var(--light-faint);
  margin-right: 0.25rem;
}
.chip {
  height: 2.25rem;
  padding: 0 0.9rem;
  border-radius: 99px;
  border: 1px solid var(--light-line);
  background: var(--light-card);
  color: var(--light-ink);
  font: 500 0.8125rem/1 var(--font-sans);
  cursor: pointer;
  transition: background-color 160ms var(--ease-out), border-color 160ms var(--ease-out);
}
.chip:hover {
  border-color: #b9c2b9;
}
.chip[aria-pressed="true"] {
  background: var(--light-ink);
  color: var(--primary);
  border-color: var(--light-ink);
}
.chip.replay {
  display: inline-grid;
  place-items: center;
  width: 2.25rem;
  padding: 0;
}

/* the knee: a mention, an offer, a column that appears when you tap */
.grow {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 1.5rem 2rem;
  align-items: start;
}
.grow .convo {
  background: var(--background);
  color: var(--foreground);
  border-radius: 1.25rem;
  padding: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  box-shadow: var(--shadow-light);
}
.grow .convo .k-bubble {
  max-width: 100%;
}
.mini {
  background: var(--light-card);
  border: 1px solid var(--light-line);
  border-radius: 1rem;
  overflow: hidden;
  box-shadow: var(--shadow-light);
}
.mini table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.mini th {
  font: 500 0.8125rem/1.2 var(--font-sans);
  color: var(--light-faint);
  text-align: right;
  padding: 0.7rem 0.8rem;
  border-bottom: 1px solid var(--light-line);
  white-space: nowrap;
}
.mini th:first-child,
.mini td:first-child {
  text-align: left;
}
.mini td {
  padding: 0.6rem 0.8rem;
  border-top: 1px solid color-mix(in oklab, var(--light-line) 70%, transparent);
  text-align: right;
  font: 400 0.875rem/1.3 var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--light-ink);
}
.mini td.dash {
  color: var(--light-faint);
}
.js .mini:not(.grown) .newc {
  display: none;
}
.mini.grown .newc {
  animation: colin 520ms var(--ease-out) both;
}
.mini th.newc {
  color: var(--light-link);
}
@keyframes colin {
  from {
    opacity: 0;
    transform: translateX(-8px);
  }
}

/* no verdicts: the two jokes, as the artifacts they come from */
.verdicts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
  align-items: start;
}
.dayfacts {
  background: var(--light-card);
  border: 2px solid var(--light-ink);
  padding: 0.5rem 0.75rem 0.75rem;
  color: var(--light-ink);
  font-size: 0.95rem;
  box-shadow: var(--shadow-light);
}
.dayfacts p {
  margin: 0;
}
.dayfacts .t {
  font: 700 2.2rem/1 var(--font-display);
  letter-spacing: -0.03em;
  margin: 0 0 0.25rem;
  padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--light-ink);
}
.dayfacts .sv {
  display: flex;
  justify-content: space-between;
  font-weight: 700;
  padding: 0.2rem 0 0.35rem;
  border-bottom: 10px solid var(--light-ink);
}
.dayfacts .hd {
  display: flex;
  justify-content: flex-end;
  font: 700 0.75rem/1.6 var(--font-sans);
  border-bottom: 4px solid var(--light-ink);
}
.dayfacts .ln {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.28rem 0;
  border-bottom: 1px solid var(--light-ink);
}
.dayfacts .ln b {
  font-weight: 700;
}
.dayfacts .ln span:last-child {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.dayfacts .foot {
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--light-soft);
  padding-top: 0.5rem;
  margin: 0;
  border-top: 6px solid var(--light-ink);
}
.stubtape {
  background: var(--paper);
  color: var(--paper-ink);
  font: 450 0.8125rem/1.6 var(--font-mono);
  padding: 1.25rem 1.1rem 1.1rem;
  rotate: 1deg;
  box-shadow: var(--shadow-light);
  -webkit-mask: linear-gradient(#000, #000) 0 10px / 100% calc(100% - 10px) no-repeat,
    conic-gradient(from -45deg at 50% 100%, #000 90deg, #0000 0) 0 0 / 14px 10px repeat-x;
  mask: linear-gradient(#000, #000) 0 10px / 100% calc(100% - 10px) no-repeat,
    conic-gradient(from -45deg at 50% 100%, #000 90deg, #0000 0) 0 0 / 14px 10px repeat-x;
}
.stubtape p {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
}
.stubtape .c {
  justify-content: center;
  color: #6a706a;
}
.stubtape .big {
  justify-content: center;
  font: 800 1.2rem/1.3 var(--font-mono);
  color: var(--paper-ink);
}
.stubtape .b {
  font-weight: 750;
}
.stubtape .hr {
  height: 0.8rem;
  background: radial-gradient(circle, #9aa09a 0.9px, transparent 1.1px) 0 50% / 7px 100% repeat-x;
}

.phones {
  --w: 16rem;
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
  align-items: flex-start;
}
.phones:has(> figure:nth-child(3)) {
  --w: 13.5rem;
}
@media (max-width: 75rem) {
  .phones:has(> figure:nth-child(3)) {
    --w: 12.5rem;
  }
}
.phones .device {
  --w: inherit;
}
.phones figure {
  margin: 0;
}
.phones figcaption {
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  color: var(--light-faint);
  max-width: var(--w);
}
.facts3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  border: 1px solid var(--light-line);
  border-radius: 1rem;
  background: var(--light-card);
  box-shadow: var(--shadow-light);
}
.facts3 > div {
  padding: 1.25rem;
}
.facts3 > div + div {
  border-left: 1px solid var(--light-line);
}
.facts3 .ico {
  width: 1.25rem;
  height: 1.25rem;
  color: var(--light-link);
  margin-bottom: 0.8rem;
}
.facts3 h3 {
  font: 600 1.05rem/1.25 var(--font-display);
  margin: 0 0 0.35rem;
}
.facts3 p {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--light-soft);
}

@media (max-width: 52rem) {
  .seam {
    grid-template-columns: 1fr;
    grid-template-rows: auto 2.25rem auto;
  }
  .seam-band {
    border: 0;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
  }
  .seam-band span {
    writing-mode: horizontal-tb;
    transform: none;
  }
  .seam-said {
    min-height: 4.2em;
  }
  .grow,
  .verdicts {
    grid-template-columns: minmax(0, 1fr);
  }
  .facts3 {
    grid-template-columns: 1fr;
  }
  .facts3 > div + div {
    border-left: 0;
    border-top: 1px solid var(--light-line);
  }
  .phones,
  .phones:has(> figure:nth-child(3)) {
    --w: min(18rem, 80vw);
  }
  .mini {
    overflow-x: auto;
  }
}

/* ------------------------------------------------------------------ reduced motion: gentler, not none */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  .js .ex.stage > .k-photo,
  .js .ex.stage > .k-bubble,
  .js .ex.stage .k > * {
    opacity: 1;
    transform: none;
  }
}

/* ================================================================== ACCURACY TABLES (/accuracy/)
   Data that genuinely is a table, on the light reading canvas. Below 40rem a row stacks:
   the first cell becomes its heading and every figure keeps its column's label beside it (data-label), so on
   a phone nothing is cut off and nothing scrolls sideways. The roles are written into the markup, because a
   table whose display changes loses its semantics in some browsers. */
.figtable {
  width: 100%;
  border-collapse: collapse;
  margin: 0.25rem 0 1.5rem;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--light-body);
}
.figtable th,
.figtable td {
  text-align: left;
  vertical-align: top;
  padding: 0.65rem 1rem 0.65rem 0;
  border-bottom: 1px solid var(--light-line);
}
.figtable th:last-child,
.figtable td:last-child {
  padding-right: 0;
}
.figtable thead th {
  font: 600 0.8125rem/1.3 var(--font-sans);
  color: var(--light-soft);
}
.figtable tbody th {
  font-weight: 500;
  color: var(--light-ink);
}
.figtable td {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.figsrc,
.figerr {
  display: block;
  font-size: 0.8125rem;
  color: var(--light-faint);
}
.figmore {
  margin: 0 0 1.5rem;
  max-width: 44rem;
}
.figmore > summary {
  cursor: pointer;
  color: var(--light-link);
  font-weight: 500;
  padding: 0.5rem 0;
  text-underline-offset: 3px;
}
.figmore > summary:hover {
  text-decoration: underline;
}
@media (max-width: 40rem) {
  .figtable thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  .figtable,
  .figtable tbody,
  .figtable tr,
  .figtable th,
  .figtable td {
    display: block;
  }
  .figtable tr {
    border-bottom: 1px solid var(--light-line);
    padding: 0.65rem 0;
  }
  .figtable th,
  .figtable td {
    border: 0;
    padding: 0.15rem 0;
    white-space: normal;
  }
  .figtable td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    text-align: right;
  }
  .figtable td::before {
    content: attr(data-label);
    color: var(--light-soft);
    text-align: left;
  }
  /* The value is ONE flex item (its figure and its note together), so it sits flush right in one column
     instead of the figure and the note splitting the row between them. */
  .figv {
    text-align: right;
  }
  .figsrc,
  .figerr {
    display: inline;
    margin-left: 0.4rem;
  }
}
