/* KKB — components layer (Air Fill).
   iOS design language in the brand skin. Depends on, and loads AFTER:
     - theme.json brand tokens   (--wp--preset--*)   color / type / space
     - assets/css/ios.css         (--ios-*)           radii / controls / motion
   BEM, single-class, token-only — no hardcoded color, space, radius, or motion.
   Reviewed: 2026-07. */

/* ---- Responsive section rhythm (steps up by breakpoint) ------------- */
:root { --section-pad: var(--wp--preset--spacing--60, 2.25rem); }
@media (min-width: 834px)  { :root { --section-pad: var(--wp--preset--spacing--70, 3.5rem); } }
@media (min-width: 1200px) { :root { --section-pad: var(--wp--preset--spacing--90, 7rem); } }

/* No sideways scroll — a bleeding decorative layer, a wide media, or a motion transform
   must never scroll the page horizontally on phones. clip (not hidden) so position:sticky
   keeps working. */
html, body { overflow-x: clip; }

/* ---- Buttons -------------------------------------------------------- */
/* Ink on gold = ~6:1 AA (paper-on-gold was ~2.8:1 and failed). */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--ios-control-height);
  padding: 0 var(--wp--preset--spacing--40);
  border: 0;
  border-radius: var(--ios-radius-md);
  background: var(--wp--preset--color--gold);
  color: var(--wp--preset--color--ink);
  font-weight: 700;
  font-size: var(--wp--preset--font-size--base);
  text-decoration: none;
  transition: transform var(--ios-duration-fast) var(--ios-ease-out),
              background-color var(--ios-duration-fast) var(--ios-ease-out);
}
.btn:active { transform: scale(0.97); }
@media (hover: hover) {
  .btn:hover { background: #E9971B; color: var(--wp--preset--color--ink); } /* darker gold (text-gradient bottom stop), not the rose pink */
}
.btn--lg {
  min-height: var(--ios-control-height-lg);
  padding-inline: var(--wp--preset--spacing--50);
  font-size: var(--wp--preset--font-size--lg);
}
/* Link-styled CTA — reads as a text link but keeps a 44px tap target (use with .btn).
   Lets the hero sit as [button] [link] rather than two stacked heavy buttons. */
.btn--link {
  background: transparent;
  box-shadow: none;
  padding-inline: var(--wp--preset--spacing--20);
  font-size: 1rem;
  font-weight: 700;
  text-decoration: underline;
  color: var(--wp--preset--color--navy);
}
.section--dark .btn--link { color: var(--wp--preset--color--gold-tint); }
@media (hover: hover) {
  .btn--link:hover { background: transparent; color: var(--wp--preset--color--paper); }
}

/* ---- Status badge — real ACF status / recommended flag -------------- */
.badge {
  display: inline-flex;
  align-items: center;
  min-height: var(--ios-control-height-sm);
  padding-inline: var(--wp--preset--spacing--20);
  border-radius: var(--ios-radius-capsule);
/*  font-size: var(--wp--preset--font-size--sm);*/
font-size: 0.7rem;
  font-weight: 700;
  line-height: 1;
}
.badge--shipped  { background: var(--wp--preset--color--sand); color: var(--wp--preset--color--ink); }
.badge--coming   { background: var(--wp--preset--color--gold-tint); color: var(--wp--preset--color--ink); }
.badge--featured { background: var(--wp--preset--color--gold); color: var(--wp--preset--color--ink); }
.badge--pro      { background: var(--wp--preset--color--gold); color: var(--wp--preset--color--ink); }
.badge--elite    { background: var(--wp--preset--color--ink); color: var(--wp--preset--color--gold-tint); }
/* Free: intentionally quiet next to Pro's solid gold — a neutral outline, not a fill. */
.badge--free     { background: transparent; color: var(--wp--preset--color--muted); box-shadow: inset 0 0 0 1px var(--wp--preset--color--line); }

/* ---- Detail hero — iOS large-title header --------------------------- */
/* Band padding comes from .section--dark; Fill owns the gold accent via --fill. */
@media (hover: hover) { .hero__back:hover { color: var(--wp--preset--color--gold-tint); } }
.hero__back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: var(--ios-tap-min);
  margin-block-end: var(--wp--preset--spacing--20);
  color: var(--wp--preset--color--paper);
  font-weight: 700;
  text-decoration: none;
}
.hero__back::before {
  content: "";
  width: 9px; height: 9px;
  border-inline-start: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: rotate(45deg);
}
.hero__label {
  display: block;
  margin-block-end: var(--wp--preset--spacing--20);
  color: var(--fill, var(--wp--preset--color--gold-tint));
  font-weight: 400;
  padding-top: 4px;
  font-size: var(--wp--preset--font-size--sm);
}
.hero__status { display: block; margin-block-end: var(--wp--preset--spacing--30); }
.hero__title { max-width: 16ch; margin: 0 0 var(--wp--preset--spacing--30); color: var(--wp--preset--color--paper); }
.hero__lead {
  max-width: 42ch;
  margin: 0;
  color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent);
  font-size: var(--wp--preset--font-size--xl); /* lede tier — outranks section intros (lg) */
  line-height: 1.4;
}
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--wp--preset--spacing--30);
  margin-block-start: var(--wp--preset--spacing--40);
}
.hero__note { margin: var(--wp--preset--spacing--30) 0 0; } /* layout only; reuse .disclaimer for color/size */
.hero--fill { --fill: var(--wp--preset--color--gold-tint); }

/* ---- Section hero (homepage) — the one commanding moment ------------ */
.section--hero { padding-block: var(--wp--preset--spacing--70, 3.5rem); }
@media (min-width: 834px)  { .section--hero { padding-block: var(--wp--preset--spacing--80, 5rem); } }
@media (min-width: 1200px) { .section--hero { padding-block: calc(var(--wp--preset--spacing--80, 5rem) + var(--wp--preset--spacing--50)); } }
.section--hero .device { --device-w: min(360px, 84vw); }
@media (min-width: 834px) {
  .section--hero .showcase__inner { grid-template-columns: 1fr 1.05fr; column-gap: var(--wp--preset--spacing--80, 5rem); }
  .section--hero .showcase__media { align-self: end; }
  .section--hero .device { --device-w: 460px; }
  /* Sub-page + archive heroes sit under the top-docked nav on tablet+. The nav occupies
     ~6.25rem from the top (its offset + em-based pill); add a spacing--80 gap on top of that
     so the eyebrow lands ~5rem below the nav. The home hero (#overview) hides its identity
     lockup for the nav instead, so it keeps the standard top padding. */
  .section--hero:not(#overview) { padding-block-start: calc(6.25rem + var(--wp--preset--spacing--80, 5rem)); }
}

/* ---- iOS inset-grouped list — feature / pain link rows -------------- */
/* Reused by front-page, both archives, and related lists on single templates
   (all grouped link lists — an inset reading measure + subtle elevation suit all). */
.card-list {
  list-style: none;
  margin: 0 auto var(--wp--preset--spacing--40);
  padding: 0;
  max-width: var(--wp--style--global--content-size, 760px);
  border: 1px solid var(--ios-hairline-color);
  border-radius: var(--ios-radius-card);
  background: var(--wp--preset--color--paper);
  box-shadow: var(--ios-elevation-1);
  overflow: hidden;
}
.card-list__item + .card-list__item { border-block-start: 0.5px solid var(--ios-hairline-color); }
.card-list__link {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: var(--ios-tap-min);
  padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
  padding-inline-end: calc(var(--wp--preset--spacing--40) + 16px);
  color: var(--wp--preset--color--ink);
  text-decoration: none;
  transition: background-color var(--ios-duration-fast) var(--ios-ease-out);
}
.card-list__link::after {
  content: "";
  position: absolute;
  inset-inline-end: var(--wp--preset--spacing--40);
  inset-block-start: 50%;
  width: 8px; height: 8px;
  border-inline-end: 2px solid var(--wp--preset--color--muted);
  border-block-start: 2px solid var(--wp--preset--color--muted);
  transform: translateY(-50%) rotate(45deg);
}
.card-list__title { font-weight: 700; color: var(--wp--preset--color--ink); }
.card-list__summary { color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--base); }
.card-list__link:active { background: var(--wp--preset--color--sand); }
@media (hover: hover) {
  .card-list__link:hover { background: var(--wp--preset--color--sand); }
}

/* ---- Gaps tile-grid — scannable gold tap-tiles (Apple category grid) --- */
/* Flat tiles (no shadow, larger radius) so they read distinct from the
   elevated compare/pricing cards. Gold-only keeps Fill's accent ownership. */
.tile-grid {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: var(--wp--style--global--wide-size, 1200px);
  display: grid;
  /* Row gap must clearly exceed the label-to-sub gap inside an item, or the grouping reads
     ambiguously — especially at one column, where every gap becomes a vertical rhythm. */
  column-gap: var(--wp--preset--spacing--40);
  row-gap: var(--wp--preset--spacing--60);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
/* Plain (non-link) tiles had no layout of their own — the label and its sub ran together. */
.tile-grid__item {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--20);
}
.tile-grid__link {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--20);
  height: 100%;
  min-height: var(--ios-tap-min);
  padding: var(--wp--preset--spacing--40);
  border-radius: var(--ios-radius-lg);
  background: var(--wp--preset--color--paper);
  border: 1px solid var(--ios-hairline-color);
  color: var(--wp--preset--color--ink);
  text-decoration: none;
  transition: transform var(--ios-duration-fast) var(--ios-ease-out),
              border-color var(--ios-duration-fast) var(--ios-ease-out);
}
.tile-grid__link:active { transform: scale(0.98); }
.tile-grid__link:focus-visible { border-radius: var(--ios-radius-lg); }
@media (hover: hover) {
  .tile-grid__link:hover { border-color: var(--wp--preset--color--gold); }
}
.tile-grid__label { display: block;font-weight: 800; font-size: var(--wp--preset--font-size--lg); line-height: 1.2; color: var(--wp--preset--color--gold); }
.tile-grid__sub { color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--base); }
.tile-grid__meta { margin-block-start: var(--wp--preset--spacing--20); } /* tier badge slot on shipped tiles */

/* Sub-page body opens with a lede — the first paragraph of the_content reads at the lede
   tier (like the hero/showcase lead) before settling into body text. Scoped to the single
   feature/gap article so it doesn't touch .content elsewhere. */
article.container > .content > p:first-of-type {
  font-size: var(--wp--preset--font-size--xl);
  line-height: 1.4;
  color: color-mix(in srgb, var(--wp--preset--color--ink) 80%, transparent);
}
/* Vertical rhythm for the single feature/gap body — comfortable paragraph gaps + heading
   space for the long-form gap pages (their subheads are real <h2>s in the body). */
article.container > .content > p { margin-block-end: var(--wp--preset--spacing--50); line-height: 1.6; }
article.container > .content > :is(h2, h3) { margin-block-start: var(--wp--preset--spacing--60); margin-block-end: var(--wp--preset--spacing--30); }
article.container > .content > :is(ul, ol) { margin-block-end: var(--wp--preset--spacing--50); padding-inline-start: var(--wp--preset--spacing--50); }
article.container > .content > :is(ul, ol) li + li { margin-block-start: var(--wp--preset--spacing--20); }

/* ---- Small text helpers -------------------------------------------- */
.muted { color: var(--wp--preset--color--muted); }
/* Default to a colour that reads on the LIGHT bands, because that is where this lands most
   often (#keep is section--sunken, #compare is a plain container). It used to be translucent
   paper unconditionally, which rendered white-on-sand — invisible. Dark contexts opt back in
   below; that is the smaller set, and getting it wrong there is a visible bug rather than an
   invisible one. */
.disclaimer {
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--sm);
}
.section--dark .disclaimer,
.section--hero .disclaimer,
.section--close .disclaimer,
.showcase--dark .disclaimer,
.site-footer .disclaimer {
  color: color-mix(in srgb, var(--wp--preset--color--paper) 66%, transparent);
}
.u-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- Device shot — framed screenshot ------------------------------- */
/* The iPhone frame is baked into the PNG; render directly + ground with a shadow
   that follows the frame's alpha. */
/* Never render a phone larger than roughly life-size (a framed iPhone ≈ 300px). */
.device { width: min(var(--device-w, 300px), 90vw); max-width: 300px; margin-inline: auto; }
/* aspect-ratio reserves space so the lazy portrait doesn't shift layout on decode */
.device__shot { display: block; width: 100%; height: auto; aspect-ratio: 1200 / 2449; filter: var(--ios-device-shadow); }
/* The home hero's still is pre-framed artwork at its own ratio, not the 1200x2449 screen
   the frame overlay assumes. Without this it inherits the wrong reserved box. */
.device__shot--hero { aspect-ratio: 1069 / 2181; }

/* ---- Feature showcase — Apple-style editorial section -------------- */
.showcase { padding-block: var(--wp--preset--spacing--60); }
@media (min-width: 834px) { .showcase { padding-block: var(--wp--preset--spacing--70, 3.5rem); } }
.showcase__inner { display: grid; gap: var(--wp--preset--spacing--50); align-items: center; }
.showcase__title { margin: 0 0 var(--wp--preset--spacing--30); font-size: var(--wp--preset--font-size--2xl); }
.showcase__lead { margin: 0 0 var(--wp--preset--spacing--40); max-width: 42ch; font-size: var(--wp--preset--font-size--lg); }
.showcase--dark .showcase__title,
.showcase--dark .showcase__lead { color: var(--wp--preset--color--paper); }

/* ---- Arrow link (reusable affordance; replaces literal arrows) ------ */
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-weight: 700;
  text-decoration: none;
  color: var(--wp--preset--color--navy);
}
.arrow-link::after {
  content: "";
  width: 0.42em; height: 0.42em;
  border-inline-end: 2px solid currentColor;
  border-block-start: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--ios-duration-fast) var(--ios-ease-out);
}
@media (hover: hover) { .arrow-link:hover::after { transform: translateX(3px) rotate(45deg); } }
.arrow-link:active { opacity: 0.6; }
.showcase--dark .arrow-link,
.section--dark .arrow-link { color: var(--wp--preset--color--gold-tint); }
/* An Air Pack cross-sell link carries its target app's brand color, not the Air Gist
   tint (matches the app-name gradient above). Add .arrow-link--<app> per app. */
.arrow-link--fill,
.section--dark .arrow-link--fill,
.showcase--dark .arrow-link--fill { color: var(--app-color-fill); }
.arrow-link--sort,
.section--dark .arrow-link--sort,
.showcase--dark .arrow-link--sort { color: var(--app-color-sort); }
.more-link { margin-block-start: var(--wp--preset--spacing--50); text-align: center; }

/* ---- Showcase / device layout at iPad and up ----------------------- */
@media (min-width: 834px) {
  .showcase__inner { grid-template-columns: 1fr 1fr; gap: var(--wp--preset--spacing--60); }
  .showcase--reverse .showcase__text { order: 2; }
  .showcase--reverse .showcase__media { order: 1; }
  .device { --device-w: 360px; }
}

/* ---- Comparison table — gold ownership of the Air Fill column ------ */
.table-wrap {
  overflow-x: auto;
  margin-block-end: var(--wp--preset--spacing--40);
  border: 1px solid var(--ios-hairline-color);
  border-radius: var(--ios-radius-card);
  background: var(--wp--preset--color--paper);
  box-shadow: var(--ios-elevation-1);
}
.compare { width: 100%; min-width: 30em; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.compare th,
.compare td {
  padding: var(--wp--preset--spacing--40);
  text-align: start;
  line-height: 1.3;
  border-block-end: 0.5px solid var(--ios-hairline-color);
}
.compare__note {
  max-width: 60ch;
  margin: var(--wp--preset--spacing--30) auto 0;
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--sm);
  text-align: center;
}
.compare thead th { font-weight: 800; font-size: var(--wp--preset--font-size--sm); color: var(--wp--preset--color--muted); }
.compare tbody th { font-weight: 600; }
.compare td { color: var(--wp--preset--color--muted); }
/* Air Fill column = a positive/"yes" column: subtle green tint + green checks. */
.compare th:last-child,
.compare td:last-child {
  background: color-mix(in srgb, var(--wp--preset--color--success) 8%, transparent);
  border-inline-start: 0.5px solid color-mix(in srgb, var(--wp--preset--color--success) 30%, var(--ios-hairline-color));
}
.compare thead th:last-child { color: var(--wp--preset--color--ink); }
.compare td:last-child { color: var(--wp--preset--color--success-deep); font-weight: 700; } /* light green fails AA as text */
.compare__none { color: var(--wp--preset--color--muted); }
.compare__check {
  display: inline-block;
  width: 0.5em; height: 0.28em;
  margin-inline-end: 0.5em;
  border-inline-start: 2px solid var(--wp--preset--color--success);
  border-block-end: 2px solid var(--wp--preset--color--success);
  transform: rotate(-45deg) translateY(-0.15em);
}

/* ---- Pricing tiers — Pro reads as recommended ---------------------- */
.tiers { display: grid; gap: var(--wp--preset--spacing--40); max-width: var(--wp--style--global--content-size, 760px); margin-inline: auto; }
.tiers:focus-visible { outline: none; box-shadow: var(--ios-focus-ring); border-radius: var(--ios-radius-lg); } /* the phone scroll track is a focusable, arrow-key-scrollable region */
/* Two plans (Free / Pro) — center the pair instead of leaving them left in a 3-col grid. */
@media (min-width: 900px) { .tiers { grid-template-columns: repeat(2, minmax(0, 360px)); justify-content: center; gap: var(--wp--preset--spacing--40); max-width: var(--wp--style--global--wide-size, 1200px); } }
/* Phone/tablet: a horizontal scroll-snap track instead of a vertical stack — each card is
   85vw so the next peeks at the edge. Full-bleeds past the container padding. */
@media (max-width: 899px) {
  .tiers {
    display: flex;
    grid-template-columns: none;
    gap: var(--wp--preset--spacing--30);
    max-width: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--wp--preset--spacing--40);
    -webkit-overflow-scrolling: touch;
    margin-inline: calc(-1 * var(--wp--preset--spacing--40));
    padding-inline: var(--wp--preset--spacing--40);
  }
  .tiers::-webkit-scrollbar { display: none; }
  .tiers { scrollbar-width: none; }
  .tier { flex: 0 0 85vw; max-width: 85vw; scroll-snap-align: start; }
}
.tier {
  position: relative;
  padding: var(--wp--preset--spacing--50);
  border: 1px solid var(--ios-hairline-color);
  border-radius: var(--ios-radius-card);
  background: var(--wp--preset--color--paper);
  box-shadow: var(--ios-elevation-1);
}
/* Featured Pro: a single, lighter emphasis — the gold border + the Recommended
   badge only. Deliberately NOT the stacked border+top-bar+elevation "hard-sell
   middle" that reads as a stock SaaS pricing grid. */
.tier--featured {
  border-width: 2px;
  border-color: var(--wp--preset--color--gold);
}
.tier__flag { margin: 0 0 var(--wp--preset--spacing--20); }
.tier__name { margin: 0; font-size: var(--wp--preset--font-size--xl); }
.tier__price { margin: 0.4rem 0 var(--wp--preset--spacing--30); font-size: var(--wp--preset--font-size--2xl); font-weight: 800; }
.tier__price-per { font-size: var(--wp--preset--font-size--base); font-weight: 600; color: var(--wp--preset--color--muted); }
.tier__list { list-style: none; margin: 0; padding: 0; }
.tier__list li { position: relative; margin-block-end: var(--wp--preset--spacing--20); padding-inline-start: 1.6em; }
.tier__list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0.15em; inset-block-start: 0.4em;
  width: 0.55em; height: 0.3em;
  border-inline-start: 2px solid var(--wp--preset--color--navy);
  border-block-end: 2px solid var(--wp--preset--color--navy);
  transform: rotate(-45deg);
}

/* ---- FAQ (native disclosure, rotating chevron) --------------------- */
.faq {
  border-block-start: 0.5px solid var(--ios-hairline-color);
  margin-block-end: var(--wp--preset--spacing--40);
  max-width: var(--wp--style--global--content-size, 760px);
  margin-inline: auto;
}
.faq__item { border-block-end: 0.5px solid var(--ios-hairline-color); }
.faq__q {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--wp--preset--spacing--30);
  padding: var(--wp--preset--spacing--30) 0;
  font-weight: 700;
  font-size: var(--wp--preset--font-size--lg);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: "";
  flex: none;
  width: 8px; height: 8px;
  border-inline-end: 2px solid var(--wp--preset--color--muted);
  border-block-end: 2px solid var(--wp--preset--color--muted);
  transform: rotate(45deg);
  transition: transform var(--ios-duration-fast) var(--ios-ease-out),
              border-color var(--ios-duration-fast) var(--ios-ease-out);
}
.faq__item[open] .faq__q::after {
  transform: rotate(-135deg);
  border-color: var(--wp--preset--color--navy);
}
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }
  .faq__item::details-content {
    block-size: 0;
    overflow: hidden;
    opacity: 0;
    transition: block-size var(--ios-duration-base) var(--ios-ease-out),
                opacity var(--ios-duration-base) var(--ios-ease-out),
                content-visibility var(--ios-duration-base) allow-discrete;
  }
  .faq__item[open]::details-content { block-size: auto; opacity: 1; }
}
.faq__a { max-width: 60ch; padding-block-end: var(--wp--preset--spacing--30); color: var(--wp--preset--color--muted); }

/* ---- Section rhythm + fixed bottom-nav clearance ------------------- */
section.container,
article.container,
.band { padding-block: var(--section-pad); }
.site-footer { padding-block-end: calc(8em + var(--ios-safe-bottom)); }
.container--tail { padding-block-end: calc(var(--section-pad) + var(--wp--preset--spacing--50)); }

/* ---- Centered section header --------------------------------------- */
.section-intro {
  max-width: 48ch;
  margin-inline: auto;
  margin-block-end: var(--wp--preset--spacing--50);
  text-align: center;
}
.section-intro > :last-child { margin-bottom: 0; }
.section-intro p { color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--lg); line-height: 1.45; }
.section--dark .section-intro p { color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent); }

/* ---- Sunken band (warm sand) for section rhythm -------------------- */
.section--sunken {
  background: var(--wp--preset--color--sand);
  padding-block: var(--section-pad);
  --ios-hairline-color: color-mix(in srgb, var(--wp--preset--color--line) 45%, var(--wp--preset--color--muted));
}

/* ---- Air Pack cross-sell roster (the one multi-accent band) -------- */
.app-row {
  list-style: none;
  margin: 0 auto;
  padding: 0;
/*  max-width: var(--wp--style--global--content-size, 760px);*/
max-width: 820px;
  display: grid;
  gap: var(--wp--preset--spacing--40);
  /* Top-align the roster. Centring worked while every app had a one-line description;
     the moment one of them is LIVE and carries a link underneath, its row grows and the
     centred rows beside it drift out of line with it. Aligning to the top means a row can
     gain a line without moving the two next to it. */
  align-items: start;
}
@media (min-width: 834px) { .app-row { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); } }
.app-row__item { display: grid; grid-template-columns: auto 1fr; column-gap: var(--wp--preset--spacing--30); align-items: start; }
.app-row__item .tile { grid-row: 1 / 3; --tile-size: 72px; box-shadow: var(--ios-elevation-2); }
@media (min-width: 834px) { .app-row__item .tile { --tile-size: 84px; } }
/* Stack, don't run inline. A live app carries a link under its description, and as an
   inline <a> it ran straight on from the sentence — "…forms for iOS Visit airfill.app".
   A flex column gives every roster entry the same shape whether or not it has a link,
   which is what the siblings will need as they ship. */
.app-row__desc {
  align-self: start;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--wp--preset--spacing--20);
  color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent);
  font-size: var(--wp--preset--font-size--sm);
}

/* ---- App name (shared — hero lockup, roster) ----------------------- */
.app-name { padding: 2px 0; font-weight: 800; font-size: var(--wp--preset--font-size--xl); line-height: 1.1; }

/* Per-app brand colours + gradients — defined here in CSS (not theme.json). Each Air Pack
   app title reads in its own gradient; solid --app-color-* is the no-background-clip fallback. */
:root {
  /* Air Fill coral — kept in sync with airfill.app's own --app-grad-fill / --app-color-fill.
     Each Air Pack app title (and its outbound link) reads in this same brand color/gradient. */
  --app-grad-fill:     linear-gradient(180deg, #ee997c 0%, #ed7559 100%);
  --app-grad-sort:     linear-gradient(180deg, #ff7ea6 0%, #e94c7d 100%);
  --app-grad-widgets:  linear-gradient(180deg, #ffc24d 0%, #e8930a 100%);
  --app-color-fill:    #ed7559;
  --app-color-sort:    #e94c7d;
  --app-color-widgets: #e8930a;
}
.app-row__head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--wp--preset--spacing--20); align-self:end; }
.app-name--fill    { color: var(--app-color-fill); }
.app-name--sort    { color: var(--app-color-sort); }
.app-name--widgets { color: var(--app-color-widgets); }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .app-name--fill, .app-name--sort, .app-name--widgets {
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
  .app-name--fill    { background-image: var(--app-grad-fill); }
  .app-name--sort    { background-image: var(--app-grad-sort); }
  .app-name--widgets { background-image: var(--app-grad-widgets); }
}
/* Coming-soon chips colour-coded to each app's gradient (ink text on the light gradient top). */
.badge--sort    { background: var(--app-grad-sort);    color: var(--wp--preset--color--ink); }
.badge--widgets { background: var(--app-grad-widgets); color: var(--wp--preset--color--ink); }

/* ---- Inline accent keyword (solid color; no gradient text) ---------- */
.u-accent { color: var(--wp--preset--color--navy); font-weight: inherit; }
.section--dark .u-accent { color: var(--wp--preset--color--gold-tint); }

/* ---- Square app-icon tile motif ------------------------------------ */
.tile {
  inline-size: var(--tile-size, 56px);
  aspect-ratio: 1 / 1;
  flex: none;
  border-radius: var(--ios-radius-icon);
  overflow: hidden;
/*  background: var(--wp--preset--color--sand);*/
  box-shadow: var(--ios-elevation-1);
}
.tile__img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Brand plate — stands in for a device (distinct shape + depth, not a fake screen) */
.tile--plate {
  --tile-size: min(300px, 72vw);
  display: grid;
  place-items: center;
  margin-inline: auto;
  border-radius: var(--ios-radius-xl);
  background: color-mix(in srgb, var(--wp--preset--color--gold) 14%, var(--wp--preset--color--sand));
  box-shadow: var(--ios-elevation-2);
}
.tile--plate .tile__img { width: 68%; height: 68%; border-radius: var(--ios-radius-icon); }
/* Honest accent placeholder for a sibling app with no icon yet */
.tile--rose  { background: var(--wp--preset--color--rose); }
.tile--amber { background: var(--wp--preset--color--amber); }

/* ---- Hero identity lockup (App Store-style icon + name + subtitle) -- */
.hero__identity { display: flex; align-items: center; gap: var(--wp--preset--spacing--30); margin-block-end: var(--wp--preset--spacing--40); }
.hero__identity .tile { --tile-size: 64px; }
.hero__identity .hero__label { margin-block-end: 0; }
.hero__ident-text { display: grid; gap: 2px; }

/* ---- Closing store card (App Store-style, benefit-led heading) ------ */
.store-card {
  display: grid;
  justify-items: center;
  gap: var(--wp--preset--spacing--30);
  max-width: 34rem;
  margin-inline: auto;
  padding: var(--wp--preset--spacing--70) var(--wp--preset--spacing--60);
  border: 1px solid var(--ios-hairline-color);
  border-radius: var(--ios-radius-card);
  background: var(--wp--preset--color--paper);
  box-shadow: var(--ios-elevation-2);
  text-align: center;
}
.store-card .tile { --tile-size: 112px; }
.store-card__title { margin: 0; font-size: var(--wp--preset--font-size--2xl); }
.store-card__sub { margin: 0; color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--lg); line-height: 1.35; }
.store-card__badge { margin: 0; }

/* ---- Official "Download on the App Store" badge (post-launch) -----------
   The <a> wraps Apple's official black badge art (assets/img/app-store-badge.svg,
   dropped in per Apple's guidelines — never recoloured). Until that asset exists,
   kkb_store_badge() adds .store-badge--fallback and we render a faithful black pill
   so the launch flip is never blocked on the art. Apple requires min height 40px
   and clear space of ≥1/4 the badge height. */
.store-badge {
  display: inline-flex;
  align-items: center;
  line-height: 0;
  border-radius: 8px; /* matches the badge art's corner so the focus ring hugs it */
}
.store-badge:focus-visible { outline: 2px solid var(--accent, var(--wp--preset--color--gold)); outline-offset: 3px; }
.store-badge img { display: block; height: 47px; width: auto; }
.store-badge--footer img { height: 44px; }
.store-badge--fallback {
  gap: .5rem;
  min-height: 47px;
  padding: 0 1.15rem;
  line-height: 1;
  background: #000;
  color: #fff;
  font-weight: 700;
  letter-spacing: .01em;
  text-decoration: none;
  border: 1px solid rgba(255,255,255,.16);
}
.store-badge--fallback::before {
  content: "";
  width: 1.2em; height: 1.2em;
  background: currentColor;
  /* Apple logo glyph */
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath d='M318.7 268c-.3-37 16.4-64.9 50.2-85.6-18.9-27.1-47.5-42-85.2-45-35.7-2.8-74.7 20.9-89 20.9-15.1 0-49.7-19.9-76.9-19.9C61.4 138.7 0 184.3 0 277.1c0 27.4 5 55.7 15 84.9 13.4 38.4 61.7 132.7 112.1 131.2 26.4-.6 45-18.7 79.4-18.7 33.3 0 50.6 18.7 79.9 18.7 50.8-.7 94.5-86.4 107.3-124.9-68.2-32.1-64.9-94.1-64.9-100.3zm-59.5-189.8C286.9 47.7 284.5 21.5 283.9 12c-25.2 1.4-54.3 17.4-71 37.2-18.4 21.2-29.2 47.4-26.9 75.1 27.2 2.1 52.5-11.9 73.2-46.1z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath d='M318.7 268c-.3-37 16.4-64.9 50.2-85.6-18.9-27.1-47.5-42-85.2-45-35.7-2.8-74.7 20.9-89 20.9-15.1 0-49.7-19.9-76.9-19.9C61.4 138.7 0 184.3 0 277.1c0 27.4 5 55.7 15 84.9 13.4 38.4 61.7 132.7 112.1 131.2 26.4-.6 45-18.7 79.4-18.7 33.3 0 50.6 18.7 79.9 18.7 50.8-.7 94.5-86.4 107.3-124.9-68.2-32.1-64.9-94.1-64.9-100.3zm-59.5-189.8C286.9 47.7 284.5 21.5 283.9 12c-25.2 1.4-54.3 17.4-71 37.2-18.4 21.2-29.2 47.4-26.9 75.1 27.2 2.1 52.5-11.9 73.2-46.1z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.store-badge--footer.store-badge--fallback { min-height: 44px; }

/* Hero slot: the badge IS the primary CTA post-launch. .hero__actions goes column-stretch
   on phones (the "primary CTA only" rule below), which would stretch the anchor away from
   the badge art's own width — hold it to its intrinsic size instead. */
.hero__actions .store-badge { align-self: start; }

/* Secondary "hear when new features ship" capture, under the primary badge. */
.store-card__updates { margin: 0; }

/* ---- Desktop vertical rhythm --------------------------------------- */
@media (min-width: 1200px) {
  .showcase { padding-block: var(--wp--preset--spacing--80, 5rem); }
  .section--hero .device { --device-w: 520px; }
}

/* ---- Immersive showcase — one oversized device on a warm stage --------- */
/* Echoes Apple's "Find a routine" centerpiece. Reuses .showcase + .device;
   always lands on a real assigned screenshot (applied to feature #1). */
.showcase--immersive {
  overflow: hidden;
  background: color-mix(in srgb, var(--wp--preset--color--gold) 6%, var(--wp--preset--color--sand));
}
.showcase--immersive .showcase__media { min-width: 0; }
.showcase--immersive .device { --device-w: min(400px, 82vw); width: min(var(--device-w, 340px), 100%); }
@media (min-width: 834px) {
  .showcase--immersive .showcase__inner { grid-template-columns: 1fr 1.05fr; column-gap: var(--wp--preset--spacing--70, 3.5rem); }
  .showcase--immersive .showcase__media { align-self: end; }
  .showcase--immersive .device { --device-w: 500px; margin-block-end: calc(-1 * var(--wp--preset--spacing--70, 3.5rem)); }
}
@media (min-width: 1200px) { .showcase--immersive .device { --device-w: 600px; } }

/* Graceful empty: if the device slot renders nothing, collapse to a text beat. */
/* Collapse the media column only when it's empty OR holds nothing but the decorative
   .hero__wash (so a lone wash from a bailed mockup can't hold it open) — but KEEP real
   non-device media like the Form Flows .flow-panel diagram. */
.showcase__media:not(:has(> :not(.hero__wash))) { display: none; }
@media (min-width: 834px) {
  .showcase__inner:has(> .showcase__media:not(:has(> :not(.hero__wash)))) { grid-template-columns: 1fr; }
}

/* ---- Staged feature chapter — a coloured "moment" per shipped story ----- */
/* Extends .showcase: reads an inline --stage-bg (a color-mix of palette tokens),
   fills a comfortable min-height on larger screens, and can carry a soft scene
   backdrop. An optional inline --stage-image (a gradient preset) paints over the
   solid --stage-bg, which stays the fallback and the photo-scrim colour. Text/media always sit above the scene. */
.showcase--stage { position: relative; overflow: hidden; background: var(--stage-bg, var(--wp--preset--color--paper)); background-image: var(--stage-image, none); }
.showcase--stage > .container { position: relative; z-index: 1; }
@media (min-width: 834px) {
  .showcase--stage { display: grid; align-content: center; min-height: min(86svh, 760px); }
}
/* Soft atmospheric backdrop (decorative, aria-hidden). Default = a warm gold wash;
   an optional <img> adds documentary context, with a directional scrim that only
   engages when a photo is present so text keeps its contrast. */
.showcase__scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: radial-gradient(120% 90% at 82% 22%, color-mix(in srgb, var(--wp--preset--color--gold) 16%, transparent), transparent 62%);
}
.showcase__scene img { width: 100%; height: 100%; object-fit: cover; opacity: 0.42; }
.showcase__scene:has(img)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    var(--stage-bg, var(--wp--preset--color--ink)) 40%,
    color-mix(in srgb, var(--stage-bg, var(--wp--preset--color--ink)) 55%, transparent) 100%);
}
.showcase--reverse .showcase__scene:has(img)::after {
  background: linear-gradient(270deg,
    var(--stage-bg, var(--wp--preset--color--ink)) 40%,
    color-mix(in srgb, var(--stage-bg, var(--wp--preset--color--ink)) 55%, transparent) 100%);
}

/* ---- Form Flows — shipped: a guided multi-form session panel ------------ */
/* Reads as a real in-app step sequence (a diagram of the flow, not a fake
   screenshot). Lives on the dark gold stage; step colour communicates state:
   done = green, current = gold, upcoming = dim, finish = gold-tint. */
.flow-panel {
  padding: var(--wp--preset--spacing--50);
  border-radius: var(--ios-radius-xl);
  background: color-mix(in srgb, var(--wp--preset--color--paper) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--wp--preset--color--paper) 16%, transparent);
  box-shadow: var(--ios-elevation-2);
}
.flow-panel__head { margin: 0 0 var(--wp--preset--spacing--40); font-weight: 800; color: var(--wp--preset--color--paper); }
.flow-panel__foot { margin: var(--wp--preset--spacing--40) 0 0; }
.flow-panel__crumb {
  display: inline-flex;
  align-items: center;
  min-height: var(--ios-control-height-sm);
  padding-inline: var(--wp--preset--spacing--30);
  border-radius: var(--ios-radius-capsule);
  background: color-mix(in srgb, var(--wp--preset--color--paper) 12%, transparent);
  color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent);
  font-size: var(--wp--preset--font-size--sm);
  font-weight: 700;
}
.flow-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--wp--preset--spacing--30); }
.flow-step {
  display: flex;
  align-items: center;
  gap: var(--wp--preset--spacing--30);
  padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
  border-radius: var(--ios-radius-md);
  background: color-mix(in srgb, var(--wp--preset--color--paper) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--wp--preset--color--paper) 16%, transparent);
  color: var(--wp--preset--color--paper);
}
.flow-step__n {
  flex: none;
  display: grid;
  place-items: center;
  width: 2em; height: 2em;
  border-radius: var(--ios-radius-capsule);
  background: color-mix(in srgb, var(--wp--preset--color--paper) 22%, transparent);
  color: var(--wp--preset--color--paper);
  font-weight: 800;
}
.flow-step--done .flow-step__n    { background: var(--wp--preset--color--success); color: var(--wp--preset--color--paper); }
.flow-step--current { border-color: color-mix(in srgb, var(--wp--preset--color--gold) 55%, transparent); }
.flow-step--current .flow-step__n { background: var(--wp--preset--color--gold); color: var(--wp--preset--color--ink); }
.flow-step--finish .flow-step__n  { background: var(--wp--preset--color--gold-tint); color: var(--wp--preset--color--ink); }
.flow-step__label { font-weight: 700; }

/* ---- Full-bleed closing band -------------------------------------------- */
/* Distinct name from .showcase--stage: this is the page's final night (navy→ink) band,
   holding the store card with clearance above the fixed bottom-nav. */
.section--close {
  background: var(--stage-bg, var(--wp--preset--color--ink));
  background-image: var(--stage-image, none);
  padding-block: var(--section-pad);
  padding-block-end: calc(var(--section-pad) + var(--wp--preset--spacing--60) + var(--ios-safe-bottom));
}

/* ---- Hero WebGL backdrop (Unicorn Studio scene) ------------------------- */
/* .showcase__scene--webgl hosts the scene AND its still frame: the frame fades up after load, shows until the
   canvas paints (hero-scene.js adds .is-ready, the canvas fades in over it) and stays for
   reduced-motion / Data Saver visitors. The device glow (.hero__wash) sits above both.
   Phones: the stacked hero is far taller than the source art (1646px), so filling it
   upscales the scene into softness. Instead the backdrop is sized off the WIDTH — it
   covers the first screen (identity, title, CTA) and fades into the ink below, keeping
   the art at or under its native resolution. From 834px it fills the whole hero. */
.section--scene { background: var(--wp--preset--color--ink); }
.section--scene > .container { position: relative; z-index: 1; }
.showcase__scene--webgl {
  bottom: auto;
  height: 150vw;
  background: url("../img/hero-scene-portrait.jpg") center / cover no-repeat;
  background-image: image-set(url("../img/hero-scene-portrait.webp") 1x, url("../img/hero-scene-portrait-2x.webp") 2x);
  -webkit-mask-image: linear-gradient(to bottom, black 55%, transparent);
  mask-image: linear-gradient(to bottom, black 55%, transparent);
}
@media (min-width: 834px) {
  .showcase__scene--webgl {
    bottom: 0;
    height: auto;
    background-image: url("../img/hero-scene.jpg");
    background-image: image-set(url("../img/hero-scene.webp") 1x, url("../img/hero-scene-2880.webp") 2x);
    -webkit-mask-image: none;
    mask-image: none;
  }
}
/* Fade the whole backdrop up from the ink, starting with the first paint. A CSS animation,
   not a class added at window load: the backdrop is the largest thing in the hero, so a late
   fade made it the page's LCP (seconds late). Gated on html.kkb-anim, so without JS or with
   reduced motion it simply shows. */
.kkb-anim .showcase__scene--webgl {
  animation: kkb-scene-in var(--ios-duration-ambient) var(--ios-ease-in-out) both;
}
@keyframes kkb-scene-in { from { opacity: 0; } to { opacity: 1; } }
/* Mirrors the art and the live scene together (per-site art direction). */
.showcase__scene--mirror { transform: scaleX(-1); }
.showcase__scene--webgl canvas {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity var(--ios-duration-ambient) var(--ios-ease-in-out);
}
.showcase__scene--webgl.is-ready canvas { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .showcase__scene--webgl canvas { display: none; }
}

/* ---- Hero ambient wash (subtle, behind the device only) ----------------- */
.section--hero { position: relative; }
.section--hero .showcase__media { position: relative; }
.hero__wash {
  position: absolute;
  /* Bleed the glow out AROUND the device so it actually reads — behind an edge-to-edge
     device on phones a confined inset:0 wash barely shows. Safe from horizontal scroll
     because html/body carry overflow-x: clip, which crops any bleed past the viewport. */
  inset: -26% -30%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(58% 52% at 50% 46%, color-mix(in srgb, var(--wp--preset--color--gold) 24%, transparent), transparent 76%);
  opacity: 1;
  transition: opacity var(--ios-duration-slow, 460ms) var(--ios-ease-out);
}
/* The glow belongs to the Air Fill clip; fade it out when Airtable-in-Safari is shown. */
.showcase__media.is-browser .hero__wash { opacity: 0; }

/* ---- Signature demo — animated ink over the screenshot's white signature box --------- */
/* Positioned over the "Approval" box in the framed signature screenshot (measured to the
   cutout). The stroke draws on quickly, holds ~5s, fades, waits ~1s, loops (CSS only). */
.sig-demo__ink {
  position: absolute;
  z-index: 2;               /* over the frame — the ink sits on the screen's signature box */
  left: 15%;
  right: 15%;
  top: 30%;
  height: 11%;
  pointer-events: none;
  overflow: visible;
}
.sig-demo__stroke {
  fill: none;
  stroke: var(--wp--preset--color--ink);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 100;    /* path normalised to pathLength="100" */
  animation: sig-write 7.7s linear infinite;
}
@keyframes sig-write {
  0%   { stroke-dashoffset: 100; opacity: 1; } /* undrawn */
  16%  { stroke-dashoffset: 0;   opacity: 1; } /* drawn on (~1.2s) */
  80%  { stroke-dashoffset: 0;   opacity: 1; } /* held ~5s */
  87%  { stroke-dashoffset: 0;   opacity: 0; } /* cleared (~0.5s fade) */
  100% { stroke-dashoffset: 0;   opacity: 0; } /* waits ~1s, then loops */
}
@media (prefers-reduced-motion: reduce) {
  .sig-demo__stroke { animation: none; stroke-dashoffset: 0; opacity: 1; } /* show it drawn, static */
}
.section--hero .showcase__media .device { position: relative; z-index: 1; }

/* ---- Arrow link as a standalone CTA (44px touch target) ----------------- */
/* Inline within prose, .arrow-link stays as-is; this modifier is for hero /
   chapter footers where it is the tappable action on its own line. */
.arrow-link--action { min-height: var(--ios-control-height);
  padding-inline: var(--wp--preset--spacing--20), 0}

/* ---- Compare: keep the row label in view while the table scrolls -------- */
.compare th[scope="row"] {
  position: sticky;
  inset-inline-start: 0;
  background: var(--wp--preset--color--paper);
  z-index: 1;
}
/* On a phone the sticky label was the whole problem rather than the fix: min-width:30em
   forced a horizontal scroll, and the pinned first column then sat on top of the two data
   columns as they slid under it — so the table read as overlapping itself. Below 640px the
   table simply fits instead: no min-width, no stickiness, nothing to overlap, and the row
   label is allowed to wrap. */
@media (max-width: 639px) {
  .compare { min-width: 0; font-size: var(--wp--preset--font-size--sm); }
  .compare th[scope="row"] {
    position: static;
    background: transparent;
    inline-size: 46%;
    hyphens: auto;
  }
  .compare th,
  .compare td { padding-inline: var(--wp--preset--spacing--20); vertical-align: top; }
  .compare thead th { font-size: var(--wp--preset--font-size--xs, 0.75rem); }
}

/* ---- Pricing: honest roadmap microcopy under the Advanced track --------- */
/* No top margin: the name, the price and this note are one block. The gaps between them
   are set by .tier__price's own top margin, so the three stay tight regardless of which of
   them a given card happens to have. */
.tier__soon {
  margin: 0 0 0;
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--sm);
}
/* Price period suffix (/yr, /mo) — smaller + muted so the number leads. */
.tier__per { font-size: var(--wp--preset--font-size--lg); font-weight: 700; color: var(--wp--preset--color--muted); }
/* Per-card action (Elite "Notify me"). */
.tier__cta { margin: var(--wp--preset--spacing--30) 0 0; }

/* ---- Impact checklist — long-requested Airtable gaps, answered (on ink) -- */
/* Apple "Get the highlights"-style scannable list; each item = green check +
   the answer + the gripe it closes. Only shipped/build-verified items appear. */
.impact-list {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: var(--wp--style--global--wide-size, 1200px);
  display: grid;
  gap: var(--wp--preset--spacing--40);
  align-items: start; /* each item sizes to its own content — a short row-neighbor isn't stretched, which was padding the quote→solution gap */
}
@media (min-width: 834px) {
  .impact-list { grid-template-columns: 1fr 1fr; column-gap: var(--wp--preset--spacing--60); }
}
/* Layout: the quote fills the row, then [check][solution] sit side by side below it — a
   grid so the solution's left edge stays justified and never wraps around the check. */
.impact-item {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--wp--preset--spacing--30);
  row-gap: var(--wp--preset--spacing--20);
  align-items: start;
}
.impact-item__check {
  grid-column: 1;
  grid-row: 2;
  display: grid;
  place-items: center;
  inline-size: 1.4rem;   /* ~30% smaller than the old 2rem */
  block-size: 1.4rem;
  font-size: 0.9rem;     /* drives the em-based checkmark so it scales with the smaller circle */
  border-radius: var(--ios-radius-capsule);
  background: var(--wp--preset--color--success);
  margin-block-start: 0.2rem; /* sit the circle with the solution's first line */
}
.impact-item__check::after {
  content: "";
  inline-size: 0.62em;
  block-size: 0.34em;
  border-inline-start: 2px solid var(--wp--preset--color--ink);
  border-block-end: 2px solid var(--wp--preset--color--ink);
  transform: rotate(-45deg) translateY(-0.06em);
}
.impact-item__t { grid-column: 1 / -1; grid-row: 1; margin: 0; font-weight: 800; font-size: var(--wp--preset--font-size--lg); line-height: 1.2; color: var(--wp--preset--color--paper); }
.impact-item__d { grid-column: 2; grid-row: 2; margin: 0; color: color-mix(in srgb, var(--wp--preset--color--paper) 78%, transparent); font-size: var(--wp--preset--font-size--base); line-height: 1.4; }
.impact-note { max-width: 64ch; margin: var(--wp--preset--spacing--50) auto 0; text-align: center; }

/* ---- Signature statement band — the one profound, typographic beat ------ */
/* Oversized Nunito, almost no chrome. The data-ownership moment before pricing. */
.statement {
/*  max-width: 22ch;*/
  margin: 0 auto; text-align: center; }
.statement__t {
  margin: 0;
  font-size: var(--wp--preset--font-size--4xl);
  line-height: 1.04;
  letter-spacing: -0.03em;
  color: var(--wp--preset--color--paper);
}
.statement__body {
  max-width: 54ch;
  margin: var(--wp--preset--spacing--50) auto 0;
  color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent);
  font-size: var(--wp--preset--font-size--xl);
  line-height: 1.5;
}
/* Three plain assurances as an iOS grouped hairline list — no icon triad. */
.assurances {
  max-width: 40rem;
  margin: var(--wp--preset--spacing--60) auto 0;
  list-style: none;
  padding: 0;
  border-radius: var(--ios-radius-card);
  border: 1px solid color-mix(in srgb, var(--wp--preset--color--paper) 16%, transparent);
  overflow: hidden;
  text-align: start;
}
.assurance {
  display: grid;
  grid-template-columns: 9rem 1fr;
  column-gap: var(--wp--preset--spacing--40);
  padding: var(--wp--preset--spacing--40);
}
.assurance + .assurance { border-block-start: 0.5px solid color-mix(in srgb, var(--wp--preset--color--paper) 14%, transparent); }
.assurance__k { font-weight: 800; color: var(--wp--preset--color--paper); }
.assurance__v { color: color-mix(in srgb, var(--wp--preset--color--paper) 80%, transparent); }
@media (max-width: 559px) {
  .assurance { grid-template-columns: 1fr; gap: var(--wp--preset--spacing--20); }
}

/* ---- Requirements / facts strip — quiet reassurance near the ask -------- */
.facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
  max-width: 60rem;
  margin: var(--wp--preset--spacing--50) auto 0;
  padding: 0;
  list-style: none;
}
.facts__item { position: relative; color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--sm); font-weight: 700; }
.facts__item + .facts__item::before {
  content: "·";
  margin-inline-end: var(--wp--preset--spacing--40);
  color: var(--wp--preset--color--line);
}

/* ---- Ghost button — quiet secondary action on dark (e.g. notify-me) ----- */
.btn--ghost {
  background: transparent;
  color: var(--wp--preset--color--paper);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--wp--preset--color--paper) 40%, transparent);
}
@media (hover: hover) {
  .btn--ghost:hover { background: color-mix(in srgb, var(--wp--preset--color--paper) 10%, transparent); color: var(--wp--preset--color--paper); }
}

/* ---- Hero h1 — display size (40 / 51 / 65px by breakpoint) --------------- */
/* Set explicitly rather than via the theme.json 4xl preset: WP's generated preset
   var isn't resolving on the page, so both .has-4xl-font-size and the base h1 rule
   fell through to the inherited 21px. The 4xl preset stays in theme.json as the
   intended source for when the global-styles emit is fixed. */
.section--hero .hero__title { font-size: 2.5rem; }                                  /* 40px — mobile */
@media (min-width: 834px)  { .section--hero .hero__title { font-size: 3.1875rem; } } /* 51px — tablet */
@media (min-width: 1200px) { .section--hero .hero__title { font-size: 4.0625rem; } } /* 65px — desktop+ */

/* ---- Hero h1 — brand gradient text (gold-h1 gradient, from theme.json) --- */
/* Source of truth is the theme.json gradient preset; the literal fallback keeps the
   title visible if WP's global-styles var isn't emitted yet (stale theme.json cache),
   since an empty background-image would clip to nothing and hide the text.
   @supports-guarded so unsupported browsers keep the solid paper title. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .section--hero#overview .hero__title,
  .bottom-nav__link.is--cta {
    background-image: var(--wp--preset--gradient--gold-h1, linear-gradient(180deg, #F6C453 0%, #E9971B 100%));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* ---- iOS bottom sheet — slide-up modal (the notify form) --------------- */
.sheet { position: fixed; inset: 0; z-index: 300; }
.sheet[hidden] { display: none; }
.sheet__scrim {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--wp--preset--color--ink) 45%, transparent);
  opacity: 0;
  transition: opacity var(--ios-duration-base) var(--ios-ease-out);
  cursor: pointer;
}
.sheet__panel {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  margin-inline: auto;
  width: 100%;
  max-width: 34rem;
  max-height: 92svh;
  display: flex;
  flex-direction: column;
  background: var(--wp--preset--color--paper);
  border-radius: var(--ios-radius-xl) var(--ios-radius-xl) 0 0; /* top corners only (mobile sheet); ≥768px rounds all four */
  box-shadow: var(--ios-elevation-sheet);
  transform: translateY(100%);
  transition: transform var(--ios-duration-base) var(--ios-ease-out);
}
.sheet--open .sheet__scrim { opacity: 1; }
.sheet--open .sheet__panel { transform: translateY(0); }
.sheet__grabber {
  flex: none;
  box-sizing: content-box;
  width: 2.25rem;
  height: 5px;
  /* transparent padding enlarges the swipe target; the visible bar stays 2.25rem × 5px */
  padding: 10px 22px;
  margin: var(--wp--preset--spacing--20) auto 0;
  border-radius: var(--ios-radius-capsule);
  background: var(--wp--preset--color--line);
  background-clip: content-box;
  position: relative;
  z-index: 10;
  touch-action: none;   /* JS owns the vertical drag (swipe-down to dismiss) */
  cursor: grab;
}
.sheet__close {
  position: absolute;
  z-index: 10;          /* above any Gravity Forms element that establishes a stacking context */
  inset-block-start: var(--wp--preset--spacing--30);
  inset-inline-end: var(--wp--preset--spacing--30);
  width: var(--ios-tap-min);
  height: var(--ios-tap-min);
  display: grid;
  place-items: center;
  border-radius: var(--ios-radius-capsule);
  background: var(--wp--preset--color--sand);
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--lg);
  line-height: 1;
  cursor: pointer;
}
.sheet__close > svg {
  pointer-events: none;   /* taps always land on the button, not the glyph */
  display: block;         /* grid-centered; no font metrics, so it lands dead center */
}
.sheet__body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--50)
           max(var(--wp--preset--spacing--50), var(--ios-safe-bottom));
}
.sheet__title { margin: 0 0 var(--wp--preset--spacing--20); font-size: var(--wp--preset--font-size--2xl); }
.sheet__lead { margin: 0 0 var(--wp--preset--spacing--40); color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--base); }
@media (prefers-reduced-motion: reduce) {
  .sheet__scrim, .sheet__panel { transition: none; }
}

/* Phone: full-bleed slide-up. Bleed the square bottom a little below the fold so no
   rounded corner or white seam shows under the browser chrome / home indicator. */
@media (max-width: 767px) {
  .sheet__panel {
    max-width: none;
    inset-block-end: calc(-1 * var(--wp--preset--spacing--50));
    padding-block-end: var(--wp--preset--spacing--50);
  }
}

/* iPad portrait and up: a floating card on the dimmed page (Apple HIG sheet anatomy) —
   rounded on all four corners, centred, sized to its content. */
@media (min-width: 768px) {
  .sheet { display: flex; align-items: center; justify-content: center; }
  .sheet__panel {
    position: relative;
    inset: auto;
    margin: 0;
    width: 100%;
    max-width: 30rem;
    max-height: min(86svh, 42rem);
    border-radius: var(--ios-radius-xl);
    transform: translateY(1.5rem);
    opacity: 0;
    transition: transform var(--ios-duration-base) var(--ios-ease-out),
                opacity var(--ios-duration-base) var(--ios-ease-out);
  }
  .sheet--open .sheet__panel { transform: translateY(0); opacity: 1; }
  .sheet__grabber { display: none; } /* drag-to-dismiss is a phone affordance */
}

/* ---- Display (4xl) size — fallback for .has-4xl-font-size headings -------- */
/* WP's generated .has-4xl-font-size rule (!important, driven by the theme.json
   preset var) isn't reaching the page yet, so this keeps every 4xl heading at
   40 / 51 / 65px instead of collapsing to the inherited size. Placed last so it
   wins source-order over the chapter/statement rules; when WP emits the preset,
   its !important rule takes over (same 40–65 range). */
.has-4xl-font-size { font-size: 2.5rem; }                                  /* 40px — mobile */
@media (min-width: 834px)  { .has-4xl-font-size { font-size: 3.1875rem; } } /* 51px — tablet */
@media (min-width: 1200px) { .has-4xl-font-size { font-size: 4.0625rem; } } /* 65px — desktop+ */

/* ---- Device-framed video — screen recording inside an empty iPhone frame -- */
/* The frame <img> defines the box + aspect; the <video> sits in the screen cutout
   behind it, rounded so its corners stay inside the frame. Insets/radius are the
   measured cutout of the iPhone 17 Pro Max frame — tunable per frame via these vars. */
.device-video {
  --dv-inset-x: 5.1%;    /* left/right bezel */
  --dv-inset-y: 2.2%;    /* top/bottom bezel */
  --dv-radius: 13% / 6%; /* two-value → stays circular as the box scales */
  position: relative;
  z-index: 1;
  width: min(var(--device-w, 300px), 90vw);
  max-width: 320px; /* never bigger than roughly life-size (matches .device's cap; a touch
                       above 300px since this is the larger Pro Max frame + its transparent margin) */
  margin-inline: auto;
}
.device-video__frame {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  filter: var(--ios-device-shadow);
}
.device-video__screen {
  
  position: absolute;
  z-index: 0;
  inset-block: var(--dv-inset-y);
  inset-inline: var(--dv-inset-x);
  width: 90%;
  height: auto;
  object-fit: cover;
  border-radius: var(--dv-radius);
  background: var(--wp--preset--color--ink);
}
/* Hero: the framed video takes the same responsive widths the static device had. */
.section--hero .device-video { --device-w: min(360px, 84vw); }
@media (min-width: 834px)  { .section--hero .device-video { --device-w: 460px; } }
@media (min-width: 1200px) { .section--hero .device-video { --device-w: 520px; } }

/* Life-size phones on every screen larger than a phone — static shots AND the framed
   video, across all contexts. The old ~300–320px cap read small on dense tablet
   displays (iPad especially), so from 600px up the device holds one consistent
   real-world size instead of shrinking. Wins over the per-context --device-w widths;
   below 600px (actual phones) the showcase device still goes edge-to-edge (rule below). */
@media (min-width: 600px) {
  .device,
  .device-video,
  .section--hero .device,
  .section--hero .device-video,
  .hero-video .device-video,
  .showcase--immersive .device,
  .showcase__media .device,
  .showcase__media .device-video { width: 360px; max-width: 360px; } /* ~life-size for the 17 Pro Max frame; 400 read slightly large on laptops */
}

/* Tablet+ docks the nav at the top with the app icon + name, so the hero's identity
   lockup is a duplicate there — hide it. Phone keeps it (nav starts hidden on load). */
@media (min-width: 834px) {
  .section--hero .hero__identity { display: none; }
}

/* ---- Hero video switcher — two recordings crossfaded, with play controls -- */
.hero-video {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--wp--preset--spacing--40);
}
.hero-video__ui { display: flex; flex-direction: column; align-items: center; gap: var(--wp--preset--spacing--30); }

/* Both screens stack in the cutout and crossfade on switch (both keep playing). */
.device-video--switch .device-video__screen {
  opacity: 0;
  transition: opacity var(--ios-duration-base) var(--ios-ease-out);
}
.device-video--switch .device-video__screen.is-active { opacity: 1; }

/* Pixel-wave wipe over the device screen on a media switch (Air Fill gold). JS sizes and
   positions this to the active screen box, so it's confined to the screen cutout — above
   both screens, and the phone frame bezel is untouched. Columns sweep horizontally in the
   direction of the segmented control (A→B left→right, B→A right→left); each column's pixels
   flash on then off, with a small random per-pixel delay for the shimmer. The settle class
   kills the crossfade for one frame at the end so the outgoing media can't flash back on
   top once the reveal completes. */
.dv-wipe {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: row;
  overflow: hidden;
  pointer-events: none;
}
.dv-wipe__col { display: flex; flex-direction: column; flex: 1 1 0; min-width: 0; }
.dv-wipe__px {
  flex: 1 1 0;
  opacity: 0;
  background: var(--wp--preset--color--gold);
  transition: opacity 0.14s linear;
}
.dv-wipe__col.is-lit .dv-wipe__px { opacity: 1; }
.dv-wipe--light .dv-wipe__px { background: var(--wp--preset--color--paper); } /* white toward the browser side (B); gold by default toward Air Fill (A) */
.device-video--switch.is-wipe-settle .device-video__screen { transition: none; }
@media (prefers-reduced-motion: reduce) { .dv-wipe { display: none; } }

/* iOS segmented control (dark hero) with a sliding, colour-changing active indicator. */
.segmented {
  position: relative;
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--ios-radius-md);
  background: color-mix(in srgb, var(--wp--preset--color--paper) 14%, transparent);
}
/* The pill that slides between segments; JS sets its width + translateX to the active
   button. Rich gold under Air Fill, light under Airtable-in-Safari. */
.segmented__ind {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  width: 0;
  border-radius: calc(var(--ios-radius-md) - 3px);
  background: var(--wp--preset--color--paper);
  transition: transform var(--ios-duration-base) var(--ios-ease-out),
              width var(--ios-duration-base) var(--ios-ease-out),
              background-color var(--ios-duration-base) var(--ios-ease-out);
  pointer-events: none;
  z-index: 0;
}
.segmented[data-active="a"] .segmented__ind { background: var(--wp--preset--color--gold); } /* rich gold on side A (Air Fill); light on side B (Safari) */
.segmented__btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--ios-control-height);
  padding-inline: var(--wp--preset--spacing--40);
  border: 0;
  border-radius: calc(var(--ios-radius-md) - 3px);
  background: transparent;
  color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent);
  font-family: inherit;
  font-weight: 700;
  font-size: var(--wp--preset--font-size--sm);
  cursor: pointer;
  transition: color var(--ios-duration-fast) var(--ios-ease-out);
}
.segmented__btn.is-active { color: var(--wp--preset--color--ink); }
.segmented__icon { width: 20px; height: 20px; border-radius: 22%; flex: none; }
@media (prefers-reduced-motion: reduce) {
  .segmented__ind { transition: none; }
}

/* Play / restart controls. */
.hero-video__controls { display: inline-flex; align-items: center; gap: var(--wp--preset--spacing--30); }
.hero-video__ctrl {
  display: grid;
  place-items: center;
  width: var(--ios-control-height);
  height: var(--ios-control-height);
  border: 0;
  border-radius: var(--ios-radius-capsule);
  background: color-mix(in srgb, var(--wp--preset--color--paper) 12%, transparent);
  color: var(--wp--preset--color--paper);
  cursor: pointer;
  transition: background-color var(--ios-duration-fast) var(--ios-ease-out);
}
@media (hover: hover) {
  .hero-video__ctrl:hover { background: color-mix(in srgb, var(--wp--preset--color--paper) 20%, transparent); }
}
.hero-video__i { display: block; width: 20px; height: 20px; fill: currentColor; }
.hero-video__i--play { display: none; }
.hero-video__ctrl.is-paused .hero-video__i--pause { display: none; }
.hero-video__ctrl.is-paused .hero-video__i--play { display: block; }

/* ---- Hero CTAs: stack full-width on small screens (cleaner than wrapping) --- */
@media (max-width: 559px) {
  .section--hero .hero__actions { flex-direction: column; align-items: stretch; }
  .section--hero .hero__actions .btn--link { display: none; } /* phone: primary CTA only */
}

/* ---- Mobile: hero + chapter devices go nearly edge-to-edge --------------- */
/* Overrides the life-size sizing on ACTUAL PHONES only (<600px) — a device recording
   reads best big there. From 600px up, the min-width:600px rule above holds a
   consistent life-size instead (iPad included). */
@media (max-width: 599px) {
  .showcase__media .device,
  .showcase__media .device-video { width: 94vw; max-width: 94vw; }
}

/* ---- Sub-page repeat control ------------------------------------------- */
/* Reused "mini-homepage" sections carry [data-kkb-reused]. When the visitor already saw
   the home page this session, the header script sets html.kkb-trim and we hide them — so
   internal navigators don't re-read the same bands. Always present in the HTML, so
   crawlers / no-JS get the full page. */
html.kkb-trim [data-kkb-reused] { display: none; }

/* ---- Site footer — breadcrumb, content hubs, house brand ---------------- */
/* Not a link-column footer (that generic Product/Company/Legal grid is banned):
   it leads with a brand + launch-list capture, then two hubs of REAL page titles,
   and closes on the house-brand mark + compliance. Lives on .section--dark. */

/* Breadcrumb trail (Yoast output; footer-scoped classes injected via filters).
   Yoast already emits the BreadcrumbList JSON-LD — this is the visible trail only. */
.crumbs { margin-block-end: var(--wp--preset--spacing--50); }
.crumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--wp--preset--spacing--20);
  font-size: var(--wp--preset--font-size--sm);
  font-weight: 700;
  line-height: 1.2;
}
.crumbs a { display: inline-flex; align-items: center; min-height: var(--ios-tap-min); color: color-mix(in srgb, var(--wp--preset--color--paper) 62%, transparent); text-decoration: none; }
.crumbs .breadcrumb_last { color: var(--wp--preset--color--paper); } /* current page */
@media (hover: hover) { .crumbs a:hover { color: var(--wp--preset--color--paper); } }
.crumbs__home { display: inline-flex; align-items: center; }
.crumbs__home-icon {
  display: block;
  width: 24px; height: 24px;
  border-radius: var(--ios-radius-icon);
  box-shadow: var(--ios-elevation-1);
}
/* CSS chevron separator (matches the site's chevron affordance) */
.crumbs__sep {
  width: 6px; height: 6px;
  border-inline-end: 2px solid color-mix(in srgb, var(--wp--preset--color--paper) 36%, transparent);
  border-block-start: 2px solid color-mix(in srgb, var(--wp--preset--color--paper) 36%, transparent);
  transform: rotate(45deg);
}

/* Main region: mobile stacks; tablet+ sets the brand/capture lead beside the hubs. */
.site-footer__main { display: grid; gap: var(--wp--preset--spacing--60); }
@media (min-width: 834px) {
  .site-footer__main {
    grid-template-columns: minmax(0, 1.5fr) 1fr 1fr;
    column-gap: var(--wp--preset--spacing--70, 3.5rem);
    align-items: start;
  }
}

/* Lead — brand lockup + launch-list capture + quick meta. */
.site-footer__lead { display: grid; gap: var(--wp--preset--spacing--40); }
.site-footer__brand { display: inline-flex; align-items: center; gap: var(--wp--preset--spacing--30); text-decoration: none; width: fit-content; }
.site-footer__brand .tile { --tile-size: 56px; }
.site-footer__ident { display: grid; gap: 2px; }
.site-footer__tagline { color: color-mix(in srgb, var(--wp--preset--color--paper) 66%, transparent); font-size: var(--wp--preset--font-size--sm); font-weight: 700; }
.site-footer__capture-title { margin: 0 0 var(--wp--preset--spacing--20); font-weight: 800; font-size: var(--wp--preset--font-size--lg); color: var(--wp--preset--color--paper); }
.site-footer__capture-line { margin: 0 0 var(--wp--preset--spacing--30); max-width: 34ch; color: color-mix(in srgb, var(--wp--preset--color--paper) 80%, transparent); }
.site-footer__capture-updates { margin: var(--wp--preset--spacing--30) 0 0; }
.site-footer__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30); margin: 0; padding: 0; list-style: none; }
.site-footer__meta a {
  display: inline-flex; align-items: center; min-height: var(--ios-tap-min);
  color: color-mix(in srgb, var(--wp--preset--color--paper) 72%, transparent);
  font-size: var(--wp--preset--font-size--sm); font-weight: 700; text-decoration: none;
}
@media (hover: hover) { .site-footer__meta a:hover { color: var(--wp--preset--color--paper); } }

/* Content hubs — dynamic, curated lists of real feature / gap page titles. */
.site-footer__hub-title { margin: 0 0 var(--wp--preset--spacing--20); font-size: var(--wp--preset--font-size--lg); font-weight: 800; color: var(--wp--preset--color--paper); }
.site-footer__list { list-style: none; margin: 0 0 var(--wp--preset--spacing--20); padding: 0; }
.site-footer__link {
  display: flex; align-items: center; min-height: var(--ios-tap-min);
  color: color-mix(in srgb, var(--wp--preset--color--paper) 82%, transparent);
  text-decoration: none; font-size: var(--wp--preset--font-size--base); line-height: 1.3;
  transition: color var(--ios-duration-fast) var(--ios-ease-out);
}
/* Interactive state = normal gold (navy is the light-surface link colour
   only; on this dark footer it must never show, incl. the ungated global a:hover). */
.site-footer__link:active { color: var(--wp--preset--color--gold); }
@media (hover: hover) { .site-footer__link:hover { color: var(--wp--preset--color--gold); } }
.site-footer__hub .arrow-link { min-height: var(--ios-control-height); font-size: var(--wp--preset--font-size--base); }

/* Base — house-brand mark, Air Pack seed, and the always-on compliance line. */
.site-footer__base {
  margin-block-start: var(--wp--preset--spacing--60);
  padding-block-start: var(--wp--preset--spacing--50);
  border-block-start: 0.5px solid color-mix(in srgb, var(--wp--preset--color--paper) 16%, transparent);
  display: grid;
  gap: var(--wp--preset--spacing--40);
}
@media (min-width: 834px) {
  .site-footer__base { grid-template-columns: 1fr auto; align-items: end; column-gap: var(--wp--preset--spacing--60); }
}
.site-footer__house { display: grid; gap: var(--wp--preset--spacing--20); }
.site-footer__kkb { display: inline-flex; align-items: center; min-height: var(--ios-tap-min); gap: var(--wp--preset--spacing--20); width: fit-content; text-decoration: none; color: var(--wp--preset--color--paper); }
.site-footer__made { color: color-mix(in srgb, var(--wp--preset--color--paper) 58%, transparent); font-size: var(--wp--preset--font-size--sm); font-weight: 700; }
.site-footer__wordmark { font-size: var(--wp--preset--font-size--sm); font-weight: 800; letter-spacing: -0.02em; color: var(--wp--preset--color--paper); }
.site-footer__airpack { margin: 0; max-width: 40ch; color: color-mix(in srgb, var(--wp--preset--color--paper) 62%, transparent); font-size: var(--wp--preset--font-size--sm); }
.site-footer__legal { max-width: 46ch; }
@media (min-width: 834px) { .site-footer__legal { text-align: end; justify-self: end; } }
.site-footer__legal .disclaimer { margin: 0; }
.site-footer__copy { margin: var(--wp--preset--spacing--20) 0 0; color: color-mix(in srgb, var(--wp--preset--color--paper) 50%, transparent); }

/* ---- Knock Knock Bang house mark (SVG line logo, gold hover-trace) ------ */
/* Faithful to the mark on knockknockbang.com, re-tokenised for this theme's dark
   footer: a light base stroke, a gold-tint hover trace that draws in per-polygon. */
/* Draw-timing is component-scoped tokens (kept faithful to the source mark's easing
   and per-polygon cadence) so no motion literal lives in a rule body. */
.site-footer {
  --kkb-logo-base: color-mix(in srgb, var(--wp--preset--color--paper) 74%, transparent);
  --kkb-logo-accent: var(--wp--preset--color--gold-tint);
  --kkb-logo-draw: 0.82s;
  --kkb-logo-draw-hover: 0.62s;
  --kkb-logo-delay: 0.2s;
  --kkb-logo-stagger: 26ms;
  --kkb-logo-ease: cubic-bezier(0.65, 0, 0.15, 1);
}
.kkb-logo { display: block; width: 32px; height: auto; overflow: visible; }
.kkb-logo__poly { fill: none; stroke-dasharray: 20; stroke-linejoin: round; stroke-width: 0.5px; }
.kkb-logo__base .kkb-logo__poly {
  stroke: var(--kkb-logo-base);
  stroke-dashoffset: 0;
  animation: kkb-logo-load-in var(--kkb-logo-draw) var(--kkb-logo-ease) both;
  animation-delay: calc(var(--kkb-logo-i, 0) * var(--kkb-logo-stagger) + var(--kkb-logo-delay));
  transition: stroke var(--ios-duration-slow) var(--ios-ease-out);
}
.kkb-logo__hover .kkb-logo__poly {
  stroke: var(--kkb-logo-accent);
  stroke-dashoffset: 20;
  transition: stroke-dashoffset var(--kkb-logo-draw-hover) var(--kkb-logo-ease), stroke var(--ios-duration-base) var(--ios-ease-out);
  transition-delay: calc((15 - var(--kkb-logo-i, 0)) * var(--kkb-logo-stagger));
}
@media (hover: hover) {
  .site-footer__kkb:hover .kkb-logo__hover .kkb-logo__poly {
    stroke-dashoffset: 0;
    transition-delay: calc(var(--kkb-logo-i, 0) * var(--kkb-logo-stagger));
  }
}
@keyframes kkb-logo-load-in {
  0%   { stroke: var(--kkb-logo-accent); stroke-dashoffset: 20; }
  65%  { stroke: var(--kkb-logo-accent); stroke-dashoffset: 0; }
  100% { stroke: var(--kkb-logo-base);   stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .kkb-logo__base .kkb-logo__poly { animation: none; stroke-dashoffset: 0; }
  .kkb-logo__hover .kkb-logo__poly,
  .site-footer__kkb:hover .kkb-logo__hover .kkb-logo__poly { transition: none; }
}

/* ---- Help center — task-oriented docs (light/doc layout) ---------------- */
/* Reuses .card-list (topic article lists), .content (article body typography),
   .section-intro (hub/topic headers). New block only for the article head + groups. */
.help-group { max-width: var(--wp--style--global--content-size, 760px); margin-inline: auto; padding-block: var(--wp--preset--spacing--50); }
.help-group + .help-group { border-block-start: 0.5px solid var(--ios-hairline-color); }
.help-group__title { margin: 0 0 var(--wp--preset--spacing--30); font-size: var(--wp--preset--font-size--xl); }
.help-group__title a { display: inline-flex; align-items: center; min-height: var(--ios-tap-min); color: var(--wp--preset--color--ink); text-decoration: none; }
@media (hover: hover) { .help-group__title a:hover { color: var(--wp--preset--color--navy); } }

.help-article__head { max-width: var(--wp--style--global--content-size, 760px); margin: 0 auto var(--wp--preset--spacing--50); }
.help-article__topic {
  display: inline-flex; align-items: center; min-height: var(--ios-tap-min);
  color: var(--wp--preset--color--navy);
  font-weight: 700; font-size: var(--wp--preset--font-size--sm); text-decoration: none;
}
@media (hover: hover) { .help-article__topic:hover { color: var(--wp--preset--color--gold); } }
.help-article__title { margin: var(--wp--preset--spacing--20) 0 var(--wp--preset--spacing--30); }
.help-article__deck { max-width: 60ch; margin: 0; color: var(--wp--preset--color--muted); font-size: var(--wp--preset--font-size--xl); line-height: 1.4; }
/* The deck IS the lede — cancel the auto-lede on the article BODY's first paragraph
   only (scoped to __body so the related/foot .content blocks keep their own styling). */
article.help-article > .help-article__body > p:first-of-type { font-size: var(--wp--preset--font-size--base); line-height: 1.6; color: inherit; }
.help-article__related, .help-article__foot { margin-block-start: var(--wp--preset--spacing--60); }
/* Compliance line — a small, quiet footnote under a divider (not body copy). */
.help-article__disclaimer {
  max-width: var(--wp--style--global--content-size, 760px);
  margin: var(--wp--preset--spacing--60) auto 0;
  padding-block-start: var(--wp--preset--spacing--40);
  border-block-start: 0.5px solid var(--ios-hairline-color);
  color: var(--wp--preset--color--muted);
  font-size: var(--wp--preset--font-size--sm);
  line-height: 1.4;
}
/* Inline code in steps (scope names, endpoints) */
.help-article .content code { padding: 0.1em 0.4em; border-radius: var(--ios-radius-xs); background: var(--wp--preset--color--sand); font-size: 0.9em; }
/* Quoted in-app strings (e.g. an on-screen banner) render as a soft callout */
.help-article .content blockquote {
  margin: var(--wp--preset--spacing--40) 0;
  padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
  border-inline-start: 3px solid var(--wp--preset--color--gold);
  border-radius: 0 var(--ios-radius-sm) var(--ios-radius-sm) 0;
  background: var(--wp--preset--color--sand);
  color: var(--wp--preset--color--muted);
}
.help-article .content blockquote > :last-child { margin-bottom: 0; }

/* App Help web-view (?app=1) — lean reading view: chrome is already gone (footer
   short-circuits, bottom nav dequeued); reclaim its safe-area clearance. */
.is-app-embed .site-main { padding-block-end: max(var(--wp--preset--spacing--60), var(--ios-safe-bottom)); }
.is-app-embed .help-article { padding-block-start: var(--wp--preset--spacing--50); }

/**
MISC UTILITIES
**/
.text-redacted {
  filter: blur(7px);
  -webkit-filter: blur(7px);
  pointer-events: none;
    /* Prevent text selection in iOS Safari and other modern browsers */
  -webkit-user-select: none; /* Safari, iOS Safari */
  user-select: none;         /* Standard syntax */
  
  /* Disable the native iOS long-press callout menu (copy/paste pop-up) */
  -webkit-touch-callout: none; 
}

/* ====================================================================
   Air Gist — widget UI lives in assets/css/widgets.css
   Split out 2026-09-02: this theme is shared with Air Fill (and the rest of Air
   Pack), and those sites render no widget mockups. Enqueued conditionally as
   `kkb-widgets` via kkb_has_widget_ui(). Do not re-add widget rules here.
   ==================================================================== */
