/* ==========================================================================
   Kairi marketing site — stylesheet
   Design tokens come straight from WEBSITE_PLAN.md brand direction.
   ========================================================================== */

:root {
  /* Brand colors */
  --color-primary: #006B64;
  --color-primary-600: #005951;
  --color-primary-700: #00453f;
  --color-sage: #D5EFEC;
  --color-sage-strong: #BFE6E1;
  --color-linen: #F8FAFA;
  --color-white: #FFFFFF;
  --color-text: #21282B;
  --color-text-secondary: #5E6668;
  --color-border: #E1E9E8;
  --color-indigo: #4E5B9C;
  --color-clay: #7C5A2D;
  --color-butter: #FFF3DE;
  --color-coral: #E48D8D;
  --color-gold: #E9C76F;

  /* Type */
  --font-display: "Nunito", "Segoe UI", sans-serif;
  --font-body: "Inter", "Segoe UI", sans-serif;

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

  /* Radius */
  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-xl: 32px;
  --radius-pill: 999px;

  /* Shadow */
  --shadow-sm: 0 1px 2px rgba(33, 40, 43, 0.06);
  --shadow-md: 0 10px 28px rgba(0, 107, 100, 0.12);
  --shadow-lg: 0 24px 56px rgba(0, 107, 100, 0.16);
  --shadow-card: 0 1px 0 rgba(33, 40, 43, 0.04);

  /* Layout */
  --container-width: 1180px;
  --header-height: 76px;
}

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

html {
  scroll-behavior: smooth;
}

@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;
  }
}

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-linen);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  display: block;
  /* Every img carries width/height attributes so the browser can reserve space
     before the file arrives. Without this, the height attribute stays in force
     when CSS overrides only the width, and the image renders stretched. */
  height: auto;
}

svg {
  width: 24px;
  height: 24px;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1.15;
  margin: 0 0 var(--space-4);
  letter-spacing: -0.01em;
}

p {
  margin: 0 0 var(--space-4);
}

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

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.article-body ul,
.legal-shell ul {
  list-style: disc;
}

button {
  font-family: inherit;
}

/* ---------- Accessibility helpers ---------- */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: var(--space-2);
  z-index: 200;
  background: var(--color-primary);
  color: #fff;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  font-weight: 700;
}

.skip-link:focus {
  left: var(--space-2);
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--color-indigo);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ---------- Layout ---------- */
.container {
  width: 100%;
  max-width: var(--container-width);
  margin: 0 auto;
  padding: 0 var(--space-5);
}

section {
  padding: var(--space-9) 0;
}

.section-head {
  max-width: 620px;
  margin: 0 0 var(--space-8);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.section-head.center {
  margin-inline: auto;
  text-align: center;
}

.eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-primary-600);
  margin-bottom: var(--space-4);
}

.section-title {
  font-size: clamp(1.9rem, 1.2rem + 2.6vw, 3rem);
  margin-bottom: var(--space-3);
  line-height: 1.15;
  text-wrap: balance;
}

.section-subtitle {
  color: var(--color-text-secondary);
  font-size: 1.05rem;
  margin-bottom: 0;
}

.highlight {
  color: var(--color-primary);
  text-decoration: underline;
  text-decoration-color: var(--color-gold);
  text-decoration-thickness: 0.09em;
  text-underline-offset: 0.14em;
  text-decoration-skip-ink: none;
}

.bg-sage {
  background: var(--color-sage);
}

.bg-white {
  background: var(--color-white);
}

.bg-linen {
  background: var(--color-linen);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1rem;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-pill);
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
  white-space: nowrap;
  min-height: 48px;
}

.btn:hover {
  transform: translateY(-1px);
}

.btn-primary {
  background: var(--color-primary);
  color: #fff;
  box-shadow: var(--shadow-md);
}

.btn-primary:hover {
  background: var(--color-primary-600);
}

.btn-secondary {
  background: transparent;
  color: var(--color-primary);
  border-color: var(--color-primary);
}

.btn-secondary:hover {
  background: var(--color-sage);
}

.btn-sm {
  padding: var(--space-2) var(--space-4);
  font-size: 0.9rem;
  min-height: 40px;
}

.btn-block {
  width: 100%;
}

/* Store badges */
.store-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: var(--space-5) 0;
}

.store-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--color-white);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  padding: 0.6rem var(--space-5);
  border-radius: var(--radius-md);
  min-height: 56px;
  transition: transform 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.store-badge:hover {
  transform: translateY(-1px);
  border-color: var(--color-primary);
  background: var(--color-linen);
}

/* The App Store badge while iOS is unreleased. build.py renders it as a
   <button> rather than a link, so it needs the button reset that an <a> does
   not — otherwise it inherits the UA's grey chrome and centred text and stops
   matching the Play badge beside it.

   Deliberately NOT dimmed the way the old .is-unavailable state was. It is not
   disabled: pressing it opens the launch-notification dialog, and a control
   that looks switched-off but does something is worse than either. */
.store-badge.is-soon {
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.btn-store.is-soon {
  font: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.store-badge svg,
.store-badge img {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
}

.store-badge .badge-text {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
  text-align: left;
}

.store-badge .badge-text small {
  font-size: 0.65rem;
  letter-spacing: 0.02em;
  opacity: 0.85;
}

.store-badge .badge-text strong {
  font-family: var(--font-display);
  font-size: 1.05rem;
}

/* ---------- iOS launch waitlist dialog ----------
   Opened by any .is-soon App Store badge. A native <dialog> rather than a
   hand-rolled overlay: focus trapping, Escape-to-close, inertness of the page
   behind it and the ::backdrop all come from the element, and every one of them
   is a thing a div-based modal gets wrong. */
.notify-dialog {
  width: min(30rem, calc(100vw - 2rem));
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-white);
  color: var(--color-text);
  box-shadow: var(--shadow-lg);
}

.notify-dialog::backdrop {
  background: rgba(33, 40, 43, 0.45);
}

.notify-form {
  position: relative;
  padding: var(--space-6);
}

.notify-close {
  position: absolute;
  top: var(--space-4);
  /* Logical, not `right`: the close button belongs in the trailing corner, and
     the site's other RTL-safe rules use the same property. */
  inset-inline-end: var(--space-4);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-text-secondary);
  cursor: pointer;
}

.notify-close:hover {
  background: var(--color-linen);
  color: var(--color-text);
}

.notify-close svg {
  width: 18px;
  height: 18px;
}

.notify-title {
  font-family: var(--font-display);
  font-size: 1.35rem;
  /* Room for the close button, so a long Danish heading does not run under it. */
  margin: 0 var(--space-7) var(--space-3) 0;
}

.notify-body {
  color: var(--color-text-secondary);
  font-size: 0.95rem;
  margin: 0 0 var(--space-5);
}

.notify-label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.notify-input {
  width: 100%;
  font: inherit;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-white);
  color: var(--color-text);
  margin-bottom: var(--space-4);
}

.notify-input:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
  border-color: var(--color-primary);
}

/* Honeypot. Moved out of view rather than display:none — the bots worth
   catching skip fields that are display:none, and a real visitor never reaches
   it because it is aria-hidden and tabindex="-1". */
.notify-hp {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.notify-status {
  font-size: 0.9rem;
  margin: var(--space-3) 0 0;
  min-height: 1.2em;
}

.notify-status.is-ok {
  color: var(--color-primary);
  font-weight: 600;
}

.notify-status.is-error {
  color: #A63D3D;
}

.trust-microcopy {
  color: var(--color-text-secondary);
  font-size: 0.92rem;
  max-width: 420px;
}

.trust-microcopy strong {
  color: var(--color-text);
}

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--color-linen);
  border-bottom: 1px solid var(--color-border);
}

.site-header .container {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: var(--header-height);
  gap: var(--space-5);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  justify-self: start;
}

.brand-icon {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
}

.brand-wordmark {
  height: 24px;
  width: auto;
  flex-shrink: 0;
}

.main-nav {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  justify-self: center;
}

.main-nav a {
  font-weight: 700;
  color: var(--color-text);
  font-size: 0.97rem;
}

.main-nav a:hover {
  color: var(--color-primary);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  justify-self: end;
}

.header-store {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* EN / DA toggle.
   Both languages are always shown with the current one marked, rather than the
   control naming only the language you would switch to. A single "DA" button is
   ambiguous in exactly the situation it matters — a Dane who has landed on the
   English page cannot tell whether it means "you are reading Danish" or "click
   for Danish". Two codes with one of them lit answers that without a word.

   Deliberately not a flag. Danish is spoken outside Denmark and a flag labels a
   country rather than a language, which is also why the codes are language
   codes and not DK. */
.lang-switch {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-sm);
  background: var(--color-sage);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.02em;
}

.lang-switch a,
.lang-switch span {
  padding: 5px var(--space-2);
  border-radius: calc(var(--radius-sm) - 3px);
  color: var(--color-text-secondary);
  line-height: 1;
}

.lang-switch a:hover {
  color: var(--color-primary);
  background: var(--color-white);
}

.lang-switch .is-current {
  background: var(--color-white);
  color: var(--color-primary);
}

/* Header language picker: a <details> disclosure, not a <select>, so the
   other language stays a real link (crawlable, hreflang) and opens with no
   JS. Sits to the right of the store buttons — the two buttons lead, the
   picker reads as a secondary control rather than competing with them. */
.lang-dropdown {
  position: relative;
}

.lang-dropdown summary {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-sage);
  color: var(--color-text-secondary);
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

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

.lang-dropdown summary:hover {
  color: var(--color-primary);
  background: var(--color-sage-strong);
}

.lang-dropdown summary svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  transition: transform 0.15s ease;
}

.lang-dropdown[open] summary svg {
  transform: rotate(180deg);
}

.lang-menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  display: flex;
  flex-direction: column;
  min-width: 130px;
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--color-white);
  box-shadow: var(--shadow-md);
  z-index: 20;
}

.lang-menu a {
  padding: var(--space-2) var(--space-3);
  border-radius: calc(var(--radius-sm) - 3px);
  color: var(--color-text);
  font-size: 0.9rem;
  font-weight: 600;
}

.lang-menu a:hover {
  background: var(--color-sage);
  color: var(--color-primary);
}

.btn-store {
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  white-space: nowrap;
  box-shadow: none;
}

.btn-store:hover {
  box-shadow: none;
}

.btn-store img {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  filter: brightness(0) invert(1);
}

.nav-toggle {
  display: none;
  border: none;
  background: var(--color-sage);
  border-radius: var(--radius-sm);
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.nav-toggle svg {
  width: 22px;
  height: 22px;
  color: var(--color-primary);
}

.mobile-nav {
  display: none;
}

/* ==========================================================================
   Landing page
   Everything from the hero down to the final CTA. Only index.html uses these,
   so they can be rewritten as a set without touching the blog, the legal pages
   or support.

   Two ideas run through it. The device frame is one component, `.device`, used
   at every size instead of the four different phone treatments the page used to
   have. And the accent green is the mascot's own #7ED321 rather than the teal:
   on the dark hero the teal disappeared, and it is the colour every gain badge
   in the app is drawn in.
   ========================================================================== */

/* ---------- Device frame ---------- */
/* One capture, one frame, one aspect. Captures do not all come back the same
   height (a stitched scroll can run short), so the frame fixes the ratio and
   crops from the top rather than letter-boxing whatever it is handed. */
.device {
  position: relative;
  width: 100%;
  max-width: 280px;
  margin-inline: auto;
  border-radius: 30px;
  padding: 7px;
  background: linear-gradient(160deg, #2b3733, #131a18);
  box-shadow: 0 22px 44px rgba(9, 32, 26, 0.28), 0 2px 6px rgba(9, 32, 26, 0.2);
}

.device picture,
.device img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 880 / 1770;
  object-fit: cover;
  object-position: top center;
  border-radius: 24px;
  background: var(--color-white);
}

/* ---------- Notification banner ---------- */
/* The one feature row whose evidence is not a screen. The capture is a strip
   with its own rounded card and shadow already drawn on it, on transparency, so
   this adds no frame of its own — a device around a notification would be
   claiming a screenshot the capture is not. Centred in the same column the
   device frames use, at the width they render at, so the row still scans as one
   of the set rather than as an image that escaped the layout. */
.banner {
  width: 100%;
  max-width: 380px;
  margin-inline: auto;
}

.banner img {
  display: block;
  width: 100%;
  height: auto;
}

/* ---------- Hero ---------- */
/* A photograph with the copy laid over its left third. Dark, to match the store
   carousel this page sits either side of, and because the one thing the hero
   has to do is not look like another wellness app.

   The dark is the section's own background as well as the scrim, so a hero that
   loses its image (a slow network, a broken path) degrades to the deep green
   panel this used to be rather than to white text on white. */
.hero {
  position: relative;
  overflow: hidden;
  display: grid;
  align-items: center;
  /* Tall enough for the photograph to be a photograph rather than a strip, but
     capped in vh so a short laptop window still shows the badges above the
     fold, which is the only thing in here that has to be clicked. */
  min-height: min(76vh, 43rem);
  padding: var(--space-9) 0;
  background:
    radial-gradient(120% 90% at 15% 0%, #12463A 0%, transparent 60%),
    linear-gradient(180deg, #0C3A2F 0%, #061E19 100%);
  color: #fff;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-media img {
  width: 100%;
  height: 100%;
  /* Beats the global `img { height: auto }`, which would otherwise let the
     photo keep its own aspect and escape the section. */
  object-fit: cover;
  /* The photo is 3:2 and the hero is nearer 2:1, so the crop is vertical on a
     desktop width: 45% keeps her head clear of the top edge and gives up the
     hem of the dress instead. Anchored right of centre because she is, which
     leaves the blurred foliage rather than her face under the copy. */
  object-position: 68% 45%;
}

/* Two scrims in one pass. The horizontal one buys the copy its contrast on the
   left and thins out to nothing over her so the picture is still a picture; the
   vertical one darkens the top for the header sitting over it and the bottom so
   the photo meets the next section instead of being cut off mid-sky.
   On a pseudo-element rather than a filter on the img, because an img cannot
   carry one. */
/* The horizontal ramp is shaped to the copy column, not to the frame: it holds
   its weight to 48% (where the text ends) and then falls off fast, instead of
   fading evenly across the whole width. That is what lets it be lighter overall
   and still measure better — an even ramp has to be dark at her face to be dark
   enough at the last line of text. Measured against the photo, the worst pixel
   under each text element clears WCAG AA: 9.6:1 for the headline, 4.8:1 for the
   green condition line, 6.9:1 for the lede, 5.3:1 for the note.

   Listed first so it composites on top of the vertical pass, which only has to
   stop the sky blowing out at the top and the frame ending abruptly at the
   bottom. Both are kept off her face, which is the one part of the picture
   there is no reason to dim. */
.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg,
      rgba(6, 30, 25, 0.93) 0%,
      rgba(6, 30, 25, 0.86) 30%,
      rgba(6, 30, 25, 0.74) 48%,
      rgba(6, 30, 25, 0.22) 62%,
      rgba(6, 30, 25, 0.06) 82%,
      rgba(6, 30, 25, 0) 100%),
    linear-gradient(180deg,
      rgba(6, 30, 25, 0.42) 0%,
      rgba(6, 30, 25, 0.06) 30%,
      rgba(6, 30, 25, 0.30) 100%);
}

.hero .container {
  position: relative;
  z-index: 1;
}

/* The copy column. Capped rather than laid out in a grid track, because the
   right of the hero is now the photograph and nothing is placed against it. */
.hero-copy {
  max-width: 34rem;
}

.hero-copy h1 {
  margin-top: var(--space-2);
  font-size: clamp(2.3rem, 1.5rem + 3vw, 3.7rem);
  line-height: 1.05;
  text-wrap: balance;
  color: #fff;
  margin-bottom: var(--space-5);
}

/* The second line qualifies the first rather than continuing it, so it is set
   noticeably smaller. At the h1's own size the condition list reads as a second
   headline competing with the promise above it, and runs to three lines. The
   inherited `text-wrap: balance` splits it evenly once it does wrap. */
.hero-copy h1 span {
  display: block;
  margin-top: 0.35em;
  font-size: 0.52em;
  line-height: 1.2;
  color: #7ED321;
}

.hero-copy .lede {
  font-size: 1.12rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.82);
  max-width: 33em;
  margin-bottom: var(--space-6);
}

.hero .store-badges {
  margin-bottom: var(--space-6);
}

.hero .store-badge {
  background: #fff;
  border-color: transparent;
}

.hero .store-badge:hover {
  background: #EAF7D6;
}

.hero-note {
  margin: 0;
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.6);
}

/* ---------- What Kairi manages: one row per feature ---------- */
/* Each row is a claim beside a capture of the screen that makes it good, and
   the rows alternate sides down the page. This replaced a four-card pillar
   list sharing one screenshot, plus a five-phone gallery lower down: between
   them every point was made twice and shown in neither place.

   Generous vertical gap because the rows have no cards, borders or shadows to
   separate them. Whitespace is what says "new idea" here, so it has to be
   larger than the gap inside a row. */
.feature-list {
  display: grid;
  gap: var(--space-9);
  position: relative;
}

/* ---------- The feature road ---------- */
/* Built and measured by script.65eec5a45b.js, which is why nothing here positions it: the
   SVG is laid over the whole list and its coordinates are the list's own.
   Behind everything, and inert, so it can pass under a phone without ever
   catching a click or a caret. */
.feature-road {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  overflow: visible;
}

.feature-row {
  position: relative;
  z-index: 1;
}

/* Stippled rather than solid: a solid line down a marketing page reads as a
   border or a divider, and this is neither. Round caps turn the dashes into
   dots, which is what makes it a trail instead of a dashed rule. */
.road-seg {
  fill: none;
  stroke: var(--color-primary);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 0.1 16;
  opacity: 0.28;
}

.road-node {
  fill: var(--color-primary);
  opacity: 0.5;
}

/* The draw-in. Clipping to the segment's own bounding box and opening it
   downward wipes the dots on in the order they are travelled, which a
   stroke-dashoffset animation cannot do here — that property is already
   spoken for by the stipple. */
.js-anim .road-seg {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.9s ease-out;
}

.js-anim .road-seg.is-paved {
  clip-path: inset(0 0 0 0);
}

.js-anim .road-node {
  opacity: 0;
  transform: scale(0.4);
  transform-origin: center;
  transform-box: fill-box;
  transition: opacity 0.4s ease-out 0.5s, transform 0.4s ease-out 0.5s;
}

.js-anim .road-node.is-paved {
  opacity: 0.5;
  transform: scale(1);
}

.feature-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: center;
  transition: opacity 0.6s ease, transform 0.6s ease;
}

/* Every other row puts the phone on the left. Source order is copy-first on
   all of them, so this is presentation only: a screen reader and a collapsed
   one-column viewport both still get the claim before the picture of it. */
.feature-row:nth-child(even) .feature-visual {
  order: -1;
}

/* The copy column is narrower than its half, so a three-line paragraph does
   not run the full width of the screenshot beside it and lose its shape. */
.feature-copy {
  max-width: 34rem;
}

/* No icon disc above the heading. It was a tinted circle carrying a generic
   stroke - a camera over "know before you eat", a clock over "plan the week" -
   which said nothing the heading beside it did not, in a row that already has a
   screenshot of the real thing for evidence. Seven of them down the page read as
   decoration keeping the headings apart. */
.feature-copy h3 {
  margin: 0 0 var(--space-3);
  font-size: 1.75rem;
  line-height: 1.2;
}

.feature-copy p {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.feature-visual {
  display: flex;
  justify-content: center;
}

.feature-visual .device {
  max-width: 290px;
}

/* ---------- Split band (copy beside a mascot) ---------- */
.split-band {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: var(--space-8);
  align-items: center;
}

.split-band .section-title {
  margin-bottom: var(--space-4);
}

.split-band .section-subtitle {
  margin-bottom: var(--space-6);
}

.split-visual {
  display: flex;
  justify-content: center;
}

.split-visual img {
  width: 280px;
  max-width: 100%;
}

.disclaimer-note {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  padding: var(--space-5);
  border-radius: var(--radius-md);
  background: var(--color-butter);
  border: 1px solid #F0E2C4;
}

.disclaimer-note svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--color-clay);
}

.disclaimer-note p {
  margin: 0;
  font-size: 0.93rem;
  color: var(--color-clay);
}

/* ---------- Four ways to scan ---------- */
/* The block now lives inside #manage, between that section's head and its
   feature rows, so it carries its own bottom gap: the section head's margin
   holds it up, and this holds the first feature row off it. A feature row is
   whole phone tall, so the gap below has to be the larger one or the cards
   look like a caption on the row underneath. */
.scan-block {
  margin-bottom: var(--space-9);
}

/* A heading, not a section title: the h2 above it is the one making the
   argument, and two display-sized lines in a row would be a fight between
   them. It is here at all so the four cards cannot be read as the four jobs
   the subtitle just named. */
.scan-head {
  font-size: 1.25rem;
  text-align: center;
  margin-bottom: var(--space-6);
}

/* Four inputs, four poses. The character does the work an icon set would do
   badly here: the difference between photographing a plate and photographing a
   menu is a difference in situation, not in noun, and a situation is what an
   illustration can carry. */
.scan-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-5);
}

.scan-card {
  display: flex;
  flex-direction: column;
  text-align: center;
}

/* A soft disc rather than a panel with a border: it groups the four poses at
   one optical size without drawing a box around each of them. */
.scan-art {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 168px;
  height: 168px;
  margin: 0 auto var(--space-5);
  border-radius: 50%;
  background: var(--color-sage);
  overflow: hidden;
}

/* Sized by height, not width: the poses have different aspect ratios (a
   standing corgi is portrait, one holding a bag of shopping is square), and
   matching their heights is what makes the row read as one set. `max-height`
   alone did not hold them — the base `img { height: auto }` rule wins — so the
   height is set outright and the panel clips whatever still runs long. */
.scan-art img {
  height: 132px;
  width: auto;
  max-width: 100%;
}

.scan-body {
  flex: 1;
  padding: 0 var(--space-3);
}

.scan-body h3 {
  font-size: 1.05rem;
  margin-bottom: var(--space-3);
}

.scan-body p {
  margin: 0;
  font-size: 0.94rem;
  color: var(--color-text-secondary);
}

/* ---------- Final CTA ---------- */
.cta-wrap {
  padding: var(--space-8) 0;
  background: var(--color-linen);
}

.final-cta {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-xl);
  padding: var(--space-8) var(--space-7);
  background:
    radial-gradient(120% 100% at 10% 0%, #12463A 0%, transparent 62%),
    linear-gradient(180deg, #0C3A2F 0%, #061E19 100%);
  color: #fff;
}

.final-cta::after {
  content: "";
  position: absolute;
  top: -90px;
  right: -90px;
  width: 280px;
  height: 280px;
  border-radius: 50%;
  border: 3px solid rgba(126, 211, 33, 0.18);
}

.final-cta .container {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  align-items: center;
  gap: var(--space-7);
  padding: 0;
  max-width: 100%;
}

.final-cta h2 {
  color: #fff;
  font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.3rem);
}

.final-cta p {
  color: rgba(255, 255, 255, 0.82);
}

.final-cta .store-badge {
  background: #fff;
  border-color: transparent;
}

.final-cta .store-badge:hover {
  background: #EAF7D6;
}

.final-cta .trust-microcopy {
  color: rgba(255, 255, 255, 0.72);
}

.final-cta-visual {
  display: flex;
  justify-content: center;
}

.final-cta-visual img {
  width: 260px;
  filter: drop-shadow(0 20px 30px rgba(0, 0, 0, 0.3));
}


/* ---------- FAQ ---------- */
.faq-head {
  position: relative;
}

.faq-mascot {
  width: 108px;
  margin: 0 auto var(--space-4);
}

.faq-list {
  max-width: 720px;
  margin: 0 auto;
  border-top: 1px solid var(--color-border);
}

/* The medical disclaimer, which moved here when the reminders section became a
   feature row. Tracks the FAQ list's column so it reads as the last item rather
   than as a banner across the page. */
#faq .disclaimer-note {
  max-width: 720px;
  margin: var(--space-6) auto 0;
}

.faq-item {
  border-bottom: 1px solid var(--color-border);
}

.faq-item.is-disclaimer summary {
  color: var(--color-indigo);
}

.faq-item summary {
  list-style: none;
  cursor: pointer;
  padding: var(--space-5) var(--space-2);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.05rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

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

.faq-item summary .faq-plus {
  width: 22px;
  height: 22px;
  color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.faq-item summary .faq-plus svg {
  width: 16px;
  height: 16px;
}

.faq-item[open] summary .faq-plus {
  transform: rotate(45deg);
}

.faq-answer {
  padding: 0 var(--space-2) var(--space-5);
  color: var(--color-text-secondary);
  max-width: 580px;
}

.faq-answer p:last-child {
  margin-bottom: 0;
}

/* ---------- Footer ---------- */
.site-footer {
  background: var(--color-white);
  border-top: 1px solid var(--color-border);
  padding: var(--space-8) 0 var(--space-6);
}

.footer-top {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr 1fr;
  gap: var(--space-6);
  padding-bottom: var(--space-6);
}

.footer-brand .brand {
  margin-bottom: var(--space-3);
}

.footer-brand p {
  color: var(--color-text-secondary);
  font-size: 0.92rem;
  max-width: 280px;
}

.footer-col h4 {
  font-family: var(--font-display);
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-secondary);
  margin-bottom: var(--space-3);
}

.footer-col ul {
  display: grid;
  gap: var(--space-2);
}

.footer-col a {
  color: var(--color-text);
  font-weight: 600;
  font-size: 0.95rem;
}

.footer-col a:hover {
  color: var(--color-primary);
}

.footer-col a.is-subtle {
  color: var(--color-text-secondary);
  font-weight: 500;
}

.footer-store-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.footer-store-links .store-badge {
  padding: 0.4rem var(--space-3);
  min-height: 40px;
}

.footer-store-links .store-badge svg,
.footer-store-links .store-badge img {
  width: 18px;
  height: 18px;
}

.footer-store-links .badge-text strong {
  font-size: 0.85rem;
}

.footer-store-links .badge-text small {
  font-size: 0.58rem;
}

.footer-bottom {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-5);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  color: var(--color-text-secondary);
  font-size: 0.85rem;
}

/* The legal entity belongs beside the copyright, not at the opposite end of
   the row: space-between would otherwise fling it to the right margin, where
   it reads as a third unrelated item rather than as who "Kairi" is. The auto
   margin takes the leftover space instead, so the two sit together and the
   disclaimer keeps the row below to itself. */
.footer-company {
  margin-right: auto;
}

/* ---------- Blog index ---------- */
.blog-hero {
  padding: var(--space-8) 0 var(--space-7);
  background: var(--color-sage);
  text-align: center;
}

.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
}

.article-card {
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  height: 100%;
  transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.6s ease;
}

.article-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
}

/* The card's picture. Bleeds to the card's edges by cancelling its padding,
   so the image is the top of the card rather than a framed inset sitting in
   it. The negative margins have to match .article-card's padding exactly. */
.article-thumb {
  display: block;
  margin: calc(var(--space-5) * -1) calc(var(--space-5) * -1) var(--space-5);
  border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 0;
  overflow: hidden;
  background: var(--color-sage);
  /* A fixed ratio, not the image's own: the heroes are a mix of portrait
     photos and square mascot PNGs, and letting each pick its own height gives
     a grid whose titles never line up. */
  aspect-ratio: 16 / 9;
}

.article-thumb img {
  width: 100%;
  height: 100%;
  /* Overrides the global `img { height: auto }`, which would otherwise beat
     the 100% here and let the image escape the ratio above. */
  object-fit: contain;
  transition: transform 0.4s ease;
}

/* Photos fill the frame and crop; mascot art is a transparent PNG that has to
   sit inside its frame or it loses the character's head to the crop. */
.article-thumb.is-photo img {
  object-fit: cover;
}

.article-card:hover .article-thumb img {
  transform: scale(1.03);
}

@media (prefers-reduced-motion: reduce) {
  .article-card:hover .article-thumb img {
    transform: none;
  }
}

.article-card .article-category {
  font-size: 0.7rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-primary);
  margin-bottom: var(--space-3);
}

.article-card h3 {
  font-size: 1.15rem;
  margin-bottom: var(--space-2);
}

.article-card h3 a {
  color: var(--color-text);
}

.article-card p {
  color: var(--color-text-secondary);
  font-size: 0.92rem;
  flex: 1;
}

.article-meta {
  display: flex;
  gap: var(--space-3);
  font-size: 0.78rem;
  color: var(--color-text-secondary);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.article-card.is-soon {
  background: var(--color-linen);
  border-style: dashed;
}

.article-card.is-soon .article-category {
  color: var(--color-text-secondary);
}

/* The category above an article title is now a link to that category's hub,
   so it needs the underline an inline link gets elsewhere on the page; it
   keeps the eyebrow styling it had as a span. */
a.article-category {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

a.article-category:hover {
  color: var(--color-primary-600);
}

.category-count {
  color: var(--color-text-secondary);
  font-size: 0.9rem;
  margin-top: var(--space-4);
}

/* ---------- Article page ---------- */
.article-shell {
  padding: var(--space-8) 0 var(--space-9);
}

.article-shell .container {
  max-width: 1080px;
}

.article-grid {
  display: grid;
  grid-template-columns: 1fr 260px;
  gap: var(--space-8);
  align-items: start;
}

.article-header {
  margin-bottom: var(--space-6);
}

.article-header .article-category {
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-primary);
  margin-bottom: var(--space-3);
  display: block;
}

.article-header h1 {
  font-size: clamp(1.8rem, 1.4rem + 1.6vw, 2.6rem);
}

.article-byline {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-text-secondary);
  font-size: 0.9rem;
  margin-top: var(--space-4);
}

.article-byline img {
  width: 36px;
  height: 36px;
  border-radius: 50%;
}

.byline-editorial-link {
  display: block;
  font-size: 0.8rem;
  color: var(--color-primary);
  text-decoration: underline;
  margin-top: 2px;
}

.article-body {
  font-size: 1.05rem;
  max-width: 680px;
}

.article-body h2 {
  font-size: 1.4rem;
  margin-top: var(--space-7);
}

.article-body h3 {
  font-size: 1.15rem;
  margin-top: var(--space-6);
}

.article-body ul,
.article-body ol {
  margin: 0 0 var(--space-4);
  padding-left: 1.3rem;
}

.article-body li {
  margin-bottom: var(--space-2);
}

.article-image {
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin: var(--space-6) 0;
  background: var(--color-sage);
  display: flex;
  justify-content: center;
  padding: var(--space-5);
}

.article-image img {
  max-width: 260px;
}

.article-image figcaption {
  text-align: center;
  font-size: 0.82rem;
  color: var(--color-text-secondary);
  padding: 0 var(--space-4) var(--space-4);
}

/* A licensed photo hero (blog-photos/) is a full-bleed photograph, not a
   small centered mascot icon, so it drops the sage padding and lets the
   image fill the container instead of capping at 260px. */
.article-image.is-photo {
  padding: 0;
  background: none;
  display: block;
}

.article-image.is-photo img {
  max-width: 100%;
  width: 100%;
  height: auto;
  display: block;
}

.photo-credit {
  text-align: center;
  font-size: 0.78rem;
  color: var(--color-text-secondary);
  margin: 0;
  padding: var(--space-2) var(--space-4) 0;
}

.article-disclaimer {
  display: flex;
  gap: var(--space-3);
  background: #f4f5fa;
  border: 1px solid var(--color-indigo);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  font-size: 0.88rem;
  color: var(--color-text-secondary);
  margin: var(--space-7) 0;
}

.article-disclaimer svg {
  width: 22px;
  height: 22px;
  color: var(--color-indigo);
  flex-shrink: 0;
}

.article-cta {
  background: var(--color-primary);
  color: #fff;
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  text-align: center;
  margin: var(--space-7) 0;
}

.article-cta h3 {
  color: #fff;
  margin-bottom: var(--space-2);
}

.article-cta p {
  color: rgba(255, 255, 255, 0.85);
  margin-bottom: var(--space-4);
}

.article-cta .store-badges {
  justify-content: center;
  margin: 0;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.article-email-cta {
  background: #f4f5fa;
  border: 1px solid var(--color-indigo);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  text-align: center;
  margin: var(--space-7) 0;
}

.article-email-cta h3 {
  margin-bottom: var(--space-2);
}

.article-email-cta p {
  color: var(--color-text-secondary);
  margin-bottom: var(--space-4);
}

.email-cta-form {
  display: flex;
  gap: var(--space-3);
  max-width: 420px;
  margin: 0 auto;
}

.email-cta-input {
  flex: 1;
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-indigo);
  border-radius: var(--radius-md);
  font-size: 0.95rem;
  font-family: inherit;
}

.email-cta-input:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.email-cta-button {
  padding: var(--space-3) var(--space-5);
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  font-size: 0.95rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}

.email-cta-button:hover {
  opacity: 0.9;
}

.email-cta-disclaimer {
  font-size: 0.8rem;
  color: var(--color-text-secondary);
  margin: var(--space-3) 0 0;
}

@media (max-width: 480px) {
  .email-cta-form {
    flex-direction: column;
  }
}

.article-sidebar {
  position: sticky;
  top: calc(var(--header-height) + var(--space-5));
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.toc-box {
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
}

.toc-box h4 {
  font-family: var(--font-display);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-secondary);
  margin-bottom: var(--space-3);
}

.toc-box ol {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--space-2);
  counter-reset: toc;
}

.toc-box li {
  counter-increment: toc;
  font-size: 0.88rem;
}

.toc-box a {
  color: var(--color-text);
  font-weight: 600;
}

.toc-box a::before {
  content: counter(toc) ". ";
  color: var(--color-primary);
  font-weight: 800;
}

.toc-box a:hover {
  color: var(--color-primary);
}

.related-box {
  background: var(--color-sage);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
}

.related-box h4 {
  font-family: var(--font-display);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-primary-600);
  margin-bottom: var(--space-3);
}

.related-box ul {
  display: grid;
  gap: var(--space-2);
}

.related-box a {
  font-weight: 700;
  font-size: 0.9rem;
}

.related-links-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
  margin-top: var(--space-5);
}

.related-links-row .article-card {
  font-size: 0.95rem;
}

/* ---------- Legal / support pages ---------- */
.legal-shell {
  padding: var(--space-8) 0 var(--space-9);
}

.legal-shell .container {
  max-width: 760px;
}

.legal-shell h1 {
  font-size: clamp(1.8rem, 1.4rem + 1.2vw, 2.4rem);
}

.legal-updated {
  color: var(--color-text-secondary);
  font-size: 0.9rem;
  margin-bottom: var(--space-7);
}

.legal-shell h2 {
  font-size: 1.25rem;
  margin-top: var(--space-7);
}

.legal-shell p,
.legal-shell li {
  color: var(--color-text-secondary);
}

.legal-shell ul {
  padding-left: 1.3rem;
  margin-bottom: var(--space-4);
}

.legal-shell li {
  margin-bottom: var(--space-2);
}

/* Support page specifics */
.support-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6);
  align-items: start;
}

.support-card {
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.support-card h2 {
  margin-top: 0;
  font-size: 1.2rem;
}

.support-visual {
  display: flex;
  justify-content: center;
}

.support-visual img {
  width: 220px;
}

.contact-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}

.contact-row:last-child {
  border-bottom: none;
}

.contact-row svg {
  width: 22px;
  height: 22px;
  color: var(--color-primary);
  flex-shrink: 0;
}

.contact-row .contact-label {
  font-size: 0.78rem;
  color: var(--color-text-secondary);
  display: block;
}

.contact-row .contact-value {
  font-weight: 700;
}

/* ---------- 404 ---------- */
.notfound-shell {
  padding: var(--space-10) 0;
  text-align: center;
}

.notfound-shell img {
  width: 220px;
  margin: 0 auto var(--space-6);
}

.notfound-shell h1 {
  font-size: clamp(1.8rem, 1.4rem + 1.6vw, 2.4rem);
}

.notfound-shell p {
  color: var(--color-text-secondary);
  max-width: 420px;
  margin-inline: auto;
}

.notfound-actions {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
  margin-top: var(--space-5);
  flex-wrap: wrap;
}

/* ==========================================================================
   Scroll reveal + hover motion
   Gated behind .js-anim (set by an inline script) so content stays fully
   visible if JavaScript never runs.
   ========================================================================== */

.js-anim .section-head:not(.is-visible),
.js-anim .feature-row:not(.is-visible),
.js-anim .support-card:not(.is-visible) {
  opacity: 0;
  transform: translateY(20px);
}

.js-anim .article-card:not(.is-visible),
.js-anim .scan-card:not(.is-visible) {
  opacity: 0;
}

/* Stagger sibling reveals slightly so grids don't pop in as one flat block */
.scan-grid > *:nth-child(2),
.blog-grid > *:nth-child(2) {
  transition-delay: 0.08s;
}

.scan-grid > *:nth-child(3),
.blog-grid > *:nth-child(3) {
  transition-delay: 0.16s;
}

.scan-grid > *:nth-child(4),
.blog-grid > *:nth-child(4) {
  transition-delay: 0.24s;
}

.blog-grid > *:nth-child(5) {
  transition-delay: 0.32s;
}

.blog-grid > *:nth-child(6) {
  transition-delay: 0.4s;
}

/* Underline sweep on nav links */
.main-nav a {
  position: relative;
}

.main-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -4px;
  width: 100%;
  height: 2px;
  background: var(--color-primary);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.2s ease;
}

.main-nav a:hover::after {
  transform: scaleX(1);
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 1023px) {
  .scan-grid,
  .blog-grid,
  .related-links-row {
    grid-template-columns: repeat(2, 1fr);
  }

  .article-grid {
    grid-template-columns: 1fr;
  }

  .article-sidebar {
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
  }

  .article-sidebar > * {
    flex: 1 1 240px;
  }

  .footer-top {
    grid-template-columns: 1.3fr 1fr 1fr;
  }
}

@media (max-width: 860px) {
  .main-nav,
  .header-store,
  /* The dropdown folds into the menu panel with the nav and the store
     buttons, rather than staying in the bar beside the burger: the panel's
     is-mobile toggle gets full-size tap targets instead of a cramped chip. */
  .lang-dropdown {
    display: none;
  }

  .nav-toggle {
    display: flex;
  }

  .split-band,
  .final-cta .container,
  .support-grid {
    grid-template-columns: 1fr;
  }

  .split-visual img {
    width: 210px;
  }

  /* One column, and the alternation goes with it: with the picture stacked
     under the copy, "left or right" has nothing left to mean, and leaving the
     order swap in place would put half the screenshots above their own copy. */
  .feature-row {
    grid-template-columns: 1fr;
    gap: var(--space-5);
  }

  .feature-row:nth-child(even) .feature-visual {
    order: 0;
  }

  .feature-list {
    gap: var(--space-8);
  }

  /* Matches the gap the rows below it use at this width, so the cards read as
     one step in the same rhythm rather than a stranded block. */
  .scan-block {
    margin-bottom: var(--space-8);
  }

  .feature-copy {
    max-width: none;
  }


  .proof-strip .container {
    grid-template-columns: 1fr;
    gap: var(--space-4);
  }

  /* The copy now covers the whole frame, so the horizontal ramp has nothing
     left to make room for and only serves to hide the photograph. Replaced
     with an even one, weighted to the bottom where the badges and note sit.

     Heavier than the desktop pass, and it has to be: there the text sits on
     blurred foliage, here it sits on her, and she is the brightest thing in
     the frame. At these values the worst pixel under the lede measures 6.0:1
     and under the green line 4.3:1, against a 3.0 threshold it clears on size
     and weight alone. The picture reads as atmosphere at this width rather
     than as something anyone studies, so the trade is cheap. */
  .hero-media::after {
    background: linear-gradient(180deg,
      rgba(6, 30, 25, 0.78) 0%,
      rgba(6, 30, 25, 0.74) 45%,
      rgba(6, 30, 25, 0.88) 100%);
  }

  /* A portrait viewport crops a landscape photo down to a narrow column, so the
     only question is which column. Her arms do not survive it at any setting;
     62% is the one that keeps her face and shoulders whole. */
  .hero-media img {
    object-position: 62% 40%;
  }

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

@media (max-width: 640px) {
  :root {
    --header-height: 64px;
  }

  section {
    padding: var(--space-7) 0;
  }

  .scan-grid,
  .blog-grid,
  .related-links-row {
    grid-template-columns: 1fr;
  }

  /* One per row on a phone, so the pose sits beside its copy instead of
     stacking into a 400px-tall card with three words in it. */
  .scan-card {
    flex-direction: row;
    align-items: stretch;
  }

  .scan-art {
    flex: 0 0 118px;
    height: auto;
    padding: var(--space-3);
    align-items: center;
  }

  .scan-art img {
    height: auto;
    width: 100%;
  }


  /* On a phone the hero is one screenful of copy, so the picture stops setting
     the height and the text does. */
  .hero {
    min-height: 0;
    padding: var(--space-8) 0;
  }

  .footer-top {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }

  .final-cta {
    padding: var(--space-7) var(--space-5);
  }

  .article-sidebar {
    flex-direction: column;
  }

  .store-badges {
    flex-direction: column;
  }
}

/* Mobile nav panel */
.mobile-nav {
  border-top: 1px solid var(--color-border);
  background: var(--color-white);
}

.mobile-nav.is-open {
  display: block;
}

.mobile-nav .container {
  height: auto;
  display: flex;
  flex-direction: column;
  padding-top: var(--space-4);
  padding-bottom: var(--space-5);
  gap: var(--space-1);
}

.mobile-nav a {
  padding: var(--space-3) var(--space-2);
  font-weight: 700;
  color: var(--color-text);
  border-radius: var(--radius-sm);
}

.mobile-nav a:hover {
  background: var(--color-sage);
  color: var(--color-primary);
}

.mobile-nav .btn {
  margin-top: var(--space-3);
}

/* In the panel the toggle sits in the flow rather than floating in a header
   that no longer has room for it, so it gets its own row and full-size targets
   instead of the compact chip. */
.lang-switch.is-mobile {
  align-self: flex-start;
  margin-top: var(--space-3);
  font-size: 0.9rem;
}

/* 14px of vertical padding rather than 8, so the hit area clears 44px with the
   3px the track adds. At var(--space-2) it came out 30px tall, which is a
   fiddly target for the one control on the page whose whole job is to rescue
   someone who cannot read the language they landed in. */
.lang-switch.is-mobile a,
.lang-switch.is-mobile span {
  padding: 14px var(--space-4);
}

.lang-switch.is-mobile a:hover {
  background: var(--color-white);
}
