/* ============================================================================
   Zorver — pre-launch landing page
   ----------------------------------------------------------------------------
   PORCELAIN. Light-first: warm paper, ink type, one deep-teal live signal.

   Design intent: the calm, airy confidence of the best wearable sites —
   enormous whitespace, few words at large size, motion that breathes — but
   editorial-serif rather than the sans everyone in this category uses, because
   the product is jewelry. Aesop or Byredo, not another fitness dashboard.

   Rules that hold the whole thing together:
   - Air is the luxury. Sections are tall; nothing is crowded.
   - One idea per screen. If a section needs a legend, it's too complex.
   - Motion is slow, weighted, and always means something — every animated
     trace is a real signal shape, not decoration.
   - Colour never carries meaning alone (8% of men are colourblind).
   ========================================================================== */

/* ---------------------------------------------------------------- tokens -- */

:root {
  /* Inverted to a dark navy ground on 6 August 2026, second colour change of
     the day: the founder wanted the whole page to look like the dark band.
     So the band's own colour became the paper, and everything that was a dark
     mark on light is now a light mark on dark. Layout and copy untouched.

     Paper IS the old band colour. The band itself had to go deeper still, or
     the page's one peak would have been the same colour as the eight sections
     around it. */
  --paper: #0B1729;
  --paper-tint: #0E1C31;
  --paper-deep: #081221;
  --card: #13233C;

  /* Lettering. Near-white with the same blue in it as the ground, so type
     sits in the navy rather than on top of it. 15.7:1 on paper. */
  --ink: #F2F6FC;
  --ink-soft: #A7B4C8;    /* 8.1:1 */
  --ink-faint: #6E7F98;   /* decorative only — 3.6:1, never body copy */

  --hairline: rgba(255, 255, 255, 0.10);
  --hairline-strong: rgba(255, 255, 255, 0.22);

  /* The accent is the band italic's pale blue, promoted. Navy #1B3A6B was the
     accent while the page was white; on a navy ground it is invisible, so the
     pair swapped roles. 8.6:1 on paper. */
  --accent: #9DBBE8;
  --accent-dim: rgba(157, 187, 232, 0.34);

  /* Live signal. Brighter than the accent so a 1.5px stroke at half opacity
     still reads — the same reasoning as the light theme, inverted. 7.2:1. */
  --signal: #6EA8E8;
  --signal-soft: rgba(110, 168, 232, 0.14);

  --ch-ecg: #F07184;
  --ch-ppg: #FF6B7D;
  --ch-eda: #E8C547;
  --ch-temp: #F79554;
  --ch-bioz: #8B9CF9;
  --ch-imu: #D98BF5;
  --ch-amb: #9BA8B7;

  --font-display: 'Instrument Serif', 'Times New Roman', serif;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Fluid scale. Generous at the top end — big type is most of the premium. */
  --step--1: clamp(0.84rem, 0.81rem + 0.15vw, 0.94rem);
  --step-0: clamp(1rem, 0.96rem + 0.22vw, 1.12rem);
  --step-1: clamp(1.15rem, 1.05rem + 0.5vw, 1.45rem);
  --step-2: clamp(1.5rem, 1.2rem + 1.4vw, 2.3rem);
  --step-3: clamp(2rem, 1.5rem + 2.4vw, 3.3rem);
  --step-4: clamp(2.6rem, 1.8rem + 3.6vw, 4.5rem);

  /* Air. These numbers do most of the "premium" work. */
  --gutter: clamp(1.35rem, 5vw, 3rem);
  --section-y: clamp(5.5rem, 13vw, 11rem);
  --measure: 34rem;
  --max: 74rem;

  --radius: 16px;
  --radius-lg: 26px;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

/* ------------------------------------------------------------ foundation -- */

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

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

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Paper grain. Very low opacity multiply — the difference between "white
   background" and "sheet of paper". Non-negotiable on a light design. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.028;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
}

img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--signal); color: var(--paper); }

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

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

/* ---------------------------------------------------------------- layout -- */

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

section { position: relative; scroll-margin-top: 5rem; }
.section-pad { padding-block: var(--section-y); }

/* Alternating grounds give the long page rhythm without any dividers. */
.ground-tint { background: var(--paper-tint); }
.ground-deep { background: var(--paper-deep); }

/* ----------------------------------------------------------- typography -- */

h1, h2 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.02;
  /* Instrument Serif is drawn loose for its size. Large settings need real
     negative tracking or the words read as separate objects instead of a
     phrase — this is most of the difference between "big text" and display
     typography. Smaller sizes get less; tracking is optical, not fixed. */
  letter-spacing: -0.032em;
  text-wrap: balance;
  font-kerning: normal;
  font-variant-ligatures: common-ligatures discretionary-ligatures;
}

h1 { font-size: var(--step-4); }

/* The hero line is longer than the one it replaced, and the column width is
   fixed by the grid, so the natural break stranded "assumed." alone on a
   fourth line — an orphan is conspicuous at display size in a serif.
   text-wrap:balance evens the words out, and because balancing happens
   between forced breaks, the roman line and the italic line each balance on
   their own rather than being pooled. Unsupported browsers get the ragged
   break, which is only less pretty, not broken.

   Safe alongside the line-splitter in app.js: that measures word offsetTop
   from live layout to assign each line its stagger index, and re-measures on
   every width change, so it reads whatever balance produced. */
.hero__copy h1 .hl { display: block; text-wrap: balance; }
h2 { font-size: var(--step-3); letter-spacing: -0.026em; }

/* ------------------------------------------------- line-by-line reveal -- */

/* Words are shells; the inner span is what moves, clipped by the shell so
   each line rises out of its own baseline. Padding on the shell keeps
   descenders and italic overhang from being sheared off by the clip. */
.w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding: 0.08em 0.06em 0.16em;
  margin: -0.08em -0.06em -0.16em;
}

.wi { display: inline-block; will-change: transform; }

/* Hidden only while scripting is confirmed live and the split hasn't happened
   yet. app.js also force-reveals on a timer, so a failure mid-script can't
   leave a heading blank. */
.js [data-lines] { opacity: 0; }
.js [data-lines].is-split { opacity: 1; }

[data-lines].is-split .wi {
  transform: translateY(105%);
  opacity: 0;
  /* Focus pull. The line doesn't just rise, it resolves — out of focus into
     sharp, the way a lens finds its subject. It costs one more property and it
     is most of the difference between "text slid up" and something that feels
     photographed. Kept short (0.75s) and small (7px): heavy blur on type reads
     as a rendering fault rather than as depth. */
  filter: blur(7px);
  /* Longhands, not the shorthand: a var() anywhere inside a shorthand turns
     the whole declaration into a pending-substitution value, which then
     interacts badly with the per-section delay overrides below. */
  transition-property: transform, opacity, filter;
  transition-duration: 1.05s, 0.6s, 0.75s;
  transition-timing-function: var(--ease), linear, var(--ease);
  transition-delay: calc(var(--i, 0) * 95ms);
}

[data-lines].is-split.is-in .wi { transform: none; opacity: 1; filter: blur(0); }

h3 {
  font-family: var(--font-sans);
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.28;
}

p { text-wrap: pretty; }

.lede { font-size: var(--step-1); line-height: 1.55; color: var(--ink-soft); max-width: var(--measure); }
.body-soft { color: var(--ink-soft); max-width: var(--measure); }

/* .body-muted was used on reserved.html's refund line and had NO rule at all,
   so the one sentence promising people their money back rendered as ordinary
   body copy — louder than the timeline above it, which is backwards. Added
   5 August 2026 during a full read of both pages. */
.body-muted {
  color: var(--ink-faint);
  max-width: var(--measure);
  font-size: var(--step--1);
  line-height: 1.6;
}

/* Eyebrow — mono small caps in bronze, with a hairline that draws itself in. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 0.85rem;
  margin-bottom: 1.75rem;
}

.eyebrow::after {
  content: '';
  height: 1px;
  flex: 1;
  max-width: 6rem;
  background: var(--accent-dim);
  transform-origin: left;
  transform: scaleX(0);
  transition: transform 1.1s var(--ease) 0.25s;
}

.reveal.is-in .eyebrow::after,
.eyebrow.is-in::after { transform: scaleX(1); }

.eyebrow--center { justify-content: center; }
.eyebrow--center::after { display: none; }

.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------- nav -- */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  padding-block: 1.15rem;
  border-bottom: 1px solid transparent;
  transition: background 0.45s var(--ease-soft), border-color 0.45s var(--ease-soft),
              backdrop-filter 0.45s var(--ease-soft);
}

.nav.is-stuck {
  background: rgba(11, 23, 41, 0.82);
  backdrop-filter: blur(18px) saturate(130%);
  -webkit-backdrop-filter: blur(18px) saturate(130%);
  border-bottom-color: var(--hairline);
}

/* Reading progress. Sits on the nav's own bottom edge so it reads as the
   hairline thickening rather than as a separate widget, and only appears once
   the nav has taken its background — at the top of the page there is nothing
   to report. */
.nav::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -1px;
  height: 1px;
  width: 100%;
  background: var(--signal);
  transform: scaleX(var(--p, 0));
  transform-origin: left;
  opacity: 0;
  transition: opacity 0.45s var(--ease-soft);
}

.nav.is-stuck::after { opacity: 0.85; }

.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

.nav__actions,
.footer__actions {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 2rem);
}

.nav__contact,
.footer__actions a {
  color: var(--ink-soft);
  font-size: 0.78rem;
  text-decoration: none;
  transition: color 0.25s var(--ease-soft);
}

.nav__contact:hover,
.footer__actions a:hover { color: var(--ink); }

/* --------------------------------------------------------- contact modal -- */

body.contact-is-open { overflow: hidden; }

.contact-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
}

.contact-modal[hidden] { display: none; }

.contact-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(3, 9, 17, 0.76);
  opacity: 0;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: opacity 0.26s var(--ease-soft);
}

.contact-modal__panel {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(calc(100% - 2rem), 37rem);
  max-height: min(90svh, 48rem);
  overflow-y: auto;
  padding: clamp(2rem, 5vw, 3.5rem);
  border: 1px solid var(--hairline-strong);
  border-radius: 28px;
  background: linear-gradient(145deg, #13243C 0%, #0C1829 74%);
  box-shadow: 0 36px 100px rgba(0, 0, 0, 0.46);
  opacity: 0;
  transform: translate(-50%, calc(-50% + 18px)) scale(0.985);
  transition: opacity 0.26s var(--ease-soft), transform 0.38s var(--ease);
}

.contact-modal.is-open .contact-modal__backdrop { opacity: 1; }
.contact-modal.is-open .contact-modal__panel { opacity: 1; transform: translate(-50%, -50%) scale(1); }

.contact-modal__close {
  position: absolute;
  top: 1.2rem;
  right: 1.2rem;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.035);
  color: var(--ink-soft);
  font: 300 1.55rem/1 var(--font-sans);
  cursor: pointer;
}

.contact-modal__panel h2 {
  max-width: 12ch;
  margin-top: 0.75rem;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 7vw, 4rem);
  font-weight: 400;
  line-height: 0.98;
  letter-spacing: -0.035em;
}

.contact-modal__intro,
.contact-modal__success > p:not(.eyebrow) {
  max-width: 28rem;
  margin-top: 1.25rem;
  color: var(--ink-soft);
  font-size: 0.98rem;
  line-height: 1.65;
}

.contact-modal__fields { display: grid; gap: 1rem; margin-top: 2rem; }
.contact-modal__fields label { display: grid; gap: 0.55rem; }
.contact-modal__fields label > span { color: var(--ink-soft); font-size: 0.78rem; }

.contact-modal__fields input,
.contact-modal__fields textarea {
  width: 100%;
  border: 1px solid var(--hairline-strong);
  border-radius: 13px;
  outline: none;
  background: rgba(4, 12, 23, 0.4);
  color: var(--ink);
  font: 400 1rem/1.5 var(--font-sans);
  transition: border-color 0.2s var(--ease-soft), box-shadow 0.2s var(--ease-soft);
}

.contact-modal__fields input { height: 3.25rem; padding: 0 1rem; }
.contact-modal__fields textarea { min-height: 8.5rem; padding: 0.9rem 1rem; resize: vertical; }
.contact-modal__fields input:focus,
.contact-modal__fields textarea:focus { border-color: var(--signal); box-shadow: 0 0 0 3px var(--signal-soft); }
.contact-modal__submit { width: 100%; margin-top: 1.25rem; }

.contact-modal__success { padding-block: 1rem; text-align: center; }
.contact-modal__success h2 { max-width: none; margin-inline: auto; }
.contact-modal__success > p:not(.eyebrow) { margin-inline: auto; }
.contact-modal__success .btn { margin-top: 2rem; }
.contact-modal__check {
  display: grid;
  width: 4.25rem;
  height: 4.25rem;
  margin: 0 auto 1.75rem;
  place-items: center;
  border: 1px solid var(--signal);
  border-radius: 50%;
  color: var(--signal);
  font-size: 1.5rem;
}

@media (max-width: 34rem) {
  .contact-modal__panel { width: calc(100% - 1rem); max-height: 94svh; border-radius: 22px; }
}

.wordmark {
  font-family: var(--font-mono);
  font-size: 0.92rem;
  font-weight: 500;
  letter-spacing: 0.44em;
  text-indent: 0.44em;
  color: var(--ink);
}

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

.hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 8rem 4rem;
}

.hero__grid { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); align-items: center; }

.hero__copy { max-width: 43rem; }

@media (min-width: 64rem) {
  .hero__grid {
    grid-template-columns: minmax(0, 1.12fr) minmax(22rem, 0.88fr);
    gap: clamp(2.5rem, 5vw, 4.25rem);
  }
}

/* Hero entrance. Everything except the headline rises on a timer, tuned to
   land behind the last line of type rather than alongside it — the eye should
   finish reading the promise before the button asks for anything. */
.hero__copy > .eyebrow,
.hero__copy > .hero__sub {
  opacity: 0;
  transform: translateY(15px);
  animation: hero-rise 1.1s var(--ease) forwards;
}

.hero__copy > .eyebrow { animation-delay: 0.08s; }
.hero__copy > .hero__sub { animation-delay: 0.78s; }

/* The eyebrow rule draws itself in — the reveal observer never runs here. */
.hero__copy > .eyebrow::after {
  animation: hero-draw 1.1s var(--ease) 0.5s forwards;
}

@keyframes hero-rise {
  to { opacity: 1; transform: none; }
}

@keyframes hero-draw {
  to { transform: scaleX(1); }
}

/* Held back a beat so the page has settled before the words start arriving. */
.hero h1.is-split .wi { transition-delay: calc(0.22s + var(--i, 0) * 105ms); }

@media (prefers-reduced-motion: reduce) {
  .hero__copy > * { opacity: 1 !important; transform: none !important; animation: none !important; }
  .hero__copy > .eyebrow::after { transform: scaleX(1) !important; }
}

.hero h1 { max-width: 19ch; margin-bottom: 1.6rem; }

/* The single italic phrase — the serif's whole reason for existing. One only,
   so it stays special. */
.hero h1 em { font-style: italic; color: var(--accent); }

.hero__sub { font-size: var(--step-1); line-height: 1.55; color: var(--ink-soft); max-width: 33ch; margin-bottom: 2.5rem; }

.hero-offer {
  overflow: hidden;
  border: 1px solid var(--hairline-strong);
  border-radius: clamp(1.35rem, 3vw, 2rem);
  background:
    radial-gradient(circle at 80% 0%, rgba(110, 168, 232, 0.12), transparent 42%),
    linear-gradient(145deg, rgba(19, 35, 60, 0.98), rgba(8, 18, 33, 0.98));
  box-shadow: 0 2rem 5rem rgba(0, 5, 15, 0.32);
  opacity: 0;
  transform: translateY(20px);
  animation: hero-rise 1.15s var(--ease) 0.62s forwards;
}

.hero-offer__media {
  position: relative;
  height: clamp(10rem, 21vw, 13.5rem);
  overflow: hidden;
  border-bottom: 1px solid var(--hairline);
}

.hero-offer__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8, 18, 33, 0.04) 46%, rgba(8, 18, 33, 0.72));
  pointer-events: none;
}

.hero-offer__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 62%;
  transform: scale(1.02);
}

.hero-offer__media--finishes {
  height: clamp(9.25rem, 17vw, 11.25rem);
  background: #F3F3F1;
}

.hero-offer__media--finishes::after {
  background: linear-gradient(180deg, rgba(8,18,33,0.02), transparent 58%, rgba(8,18,33,0.13));
}

.hero-offer__finishes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  height: 100%;
  background: #D8DCE1;
  gap: 1px;
}

.hero-offer__finishes figure {
  position: relative;
  min-width: 0;
  overflow: hidden;
  background: #F6F6F4;
}

.hero-offer__media--finishes .hero-offer__finishes img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 69%;
  transform: none;
}

.hero-offer__finishes figcaption {
  position: absolute;
  z-index: 1;
  left: 50%;
  bottom: 0.55rem;
  padding: 0.3rem 0.48rem;
  border: 1px solid rgba(8,18,33,0.12);
  border-radius: 999px;
  background: rgba(250,250,248,0.82);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #172237;
  font-family: var(--font-mono);
  font-size: 0.5rem;
  line-height: 1;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translateX(-50%);
}

.hero-offer__badge {
  position: absolute;
  z-index: 1;
  top: 1rem;
  left: 1rem;
  padding: 0.48rem 0.7rem;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 999px;
  background: rgba(8, 18, 33, 0.44);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.61rem;
  line-height: 1;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.hero-offer__body { padding: clamp(1.3rem, 3vw, 1.75rem); }

.hero-offer h2 {
  font-size: clamp(1.8rem, 2.8vw, 2.45rem);
  line-height: 1;
  letter-spacing: -0.025em;
}

.hero-offer__intro {
  margin-top: 0.55rem;
  color: var(--ink-soft);
  font-size: var(--step--1);
}

.hero-offer__value-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-top: 1.3rem;
  border-block: 1px solid var(--hairline);
}

.hero-offer__value { padding-block: 1rem; }
.hero-offer__value + .hero-offer__value {
  padding-left: 1rem;
  border-left: 1px solid var(--hairline);
}

.hero-offer__value > span {
  display: block;
  color: var(--ink-soft);
  font-size: 0.76rem;
  line-height: 1.25;
}

.hero-offer__value strong {
  display: block;
  margin-top: 0.4rem;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: clamp(1.65rem, 2.8vw, 2.15rem);
  font-weight: 400;
  line-height: 1;
}

.hero-offer__value small {
  display: block;
  margin-top: 0.35rem;
  color: var(--ink-faint);
  font-size: 0.66rem;
  letter-spacing: 0.02em;
}

.hero-offer__benefits {
  display: grid;
  gap: 0.62rem;
  margin-block: 1.15rem;
  list-style: none;
  color: var(--ink-soft);
  font-size: 0.76rem;
  line-height: 1.35;
}

.hero-offer__benefits li {
  position: relative;
  padding-left: 1.3rem;
}

.hero-offer__benefits li::before {
  content: '✓';
  position: absolute;
  left: 0;
  top: 0;
  color: var(--signal);
  font-weight: 700;
}

.hero-offer__cta { width: 100%; margin-top: 1.25rem; }

.hero-offer__note {
  margin-top: 0.6rem;
  color: var(--ink-faint);
  font-size: 0.68rem;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .hero-offer { opacity: 1 !important; transform: none !important; animation: none !important; }
}

/* --------------------------------------------------------------- button -- */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 3.6rem;
  padding: 0 2rem;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  overflow: hidden;
  white-space: nowrap;
  box-shadow: 0 1px 2px rgba(10,14,22,0.10), 0 10px 28px -12px rgba(10,14,22,0.45);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease);
/* The button briefly had a magnetic pull toward the cursor (5 Aug 2026).
   Removed at the founder's call: the CTA should sit still. The hover lift and
   the specular sweep below stay — those are the reward for arriving, not a
   reason to chase the thing around the screen. */
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(10,14,22,0.12), 0 18px 38px -14px rgba(10,14,22,0.5);
}
.btn:active { transform: scale(0.985) translateY(0); transition-duration: 0.09s; }

/* Specular sweep on hover — polished, not glossy. */
.btn::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 36%, rgba(255,255,255,0.22) 50%, transparent 64%);
  transform: translateX(-130%);
  transition: transform 0.95s var(--ease);
}

.btn:hover::after { transform: translateX(130%); }

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--hairline-strong);
  box-shadow: none;
}
.btn--ghost:hover { background: rgba(10,14,22,0.04); box-shadow: none; transform: translateY(-1px); }
.btn--ghost::after { display: none; }

.btn--sm { min-height: 2.85rem; padding: 0 1.3rem; font-size: 0.9rem; }

.btn__price { font-family: var(--font-mono); font-variant-numeric: tabular-nums; opacity: 0.6; font-weight: 500; }

/* -------------------------------------------------------- product shots -- */

/* Each render carries its own warm off-white ground and lighting, so the job
   here is restraint: a soft frame, matched background, and no cropping. */
.shot {
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Sampled from the renders' own corners (#EDEFF4) so no seam shows where
     the image meets the frame. The frame also hugs the image via fit-content,
     so in practice there is nothing to see either side. */
  background: #EDEFF4; /* stays light — the renders are on white */
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  border: 1px solid var(--hairline);
  box-shadow: 0 1px 2px rgba(10,14,22,0.04), 0 34px 70px -46px rgba(10,14,22,0.38);
  display: grid;
  /* Centre rather than stretch — a grid item defaults to filling its column,
     which was silently scaling the images past their real pixel count. */
  justify-items: center;
  align-content: center;
}

/* Never upscaled. The source composite gives each panel only ~320x600 real
   pixels, so rendering them any larger just interpolates — which is exactly
   what made the first pass look soft. Images sit at their natural size,
   centred, and the frame's ground is matched to the render's own so the
   surrounding space reads as deliberate margin rather than letterboxing. */
.shot img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
}


/* The renders carry their own pale ground, which is a shade cooler than the
   paper — so every shot needs its frame, or it reads as a stray grey
   rectangle. Rounded, hairlined, and lifted just enough to sit on the page. */
.shot img { border-radius: calc(var(--radius-lg) - 1px); }

/* The hero used to drift slowly up and down — a cut-out product on white reads
   as an object suspended in space, and the motion sold that. The hero is a
   photograph now, and a photograph of a person cannot float: the whole frame
   bobbing looks like a rendering fault, not weightlessness. Removed with the
   render it belonged to rather than left running on an image it fights. */

/* The options grid — one finish per column.
   ----------------------------------------------------------------------------
   Was four cut-out renders on near-white, then four photographs on black; is
   now two, since the capsule was dropped on 4 August 2026 and the product is
   the bar alone. The plate is .shot--dark and the caption strip inverts with
   it.

   The evenness is done in the pixels, not here. Both images are cropped to an
   exact 4:5 with the necklace at the same width and height in the frame, so
   these rules only have to stretch each one to its column and the pair lines
   up on its own. The previous set fought this in CSS for weeks and never won,
   because you cannot talk differently-scaled objects into looking like one
   set. */
.options {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.1rem, 3vw, 1.75rem);
  margin-top: clamp(3rem, 7vw, 4.5rem);
}

/* Stacked, then two, then three — one column per finish. Gold joined rose
   gold and silver on 5 August 2026, so the two-column terminal state that
   replaced the old four-column rule became a three-item grid with one orphan
   on the second row. Add a column here whenever a finish is added, and check
   the upscale note below: at three across each render renders smaller, so
   there is more headroom, not less. */
@media (min-width: 34rem) { .options { grid-template-columns: 1fr 1fr; } }
@media (min-width: 62rem) { .options { grid-template-columns: repeat(3, 1fr); } }

.options .shot { width: 100%; }
.options .shot img { width: 100%; }

/* Dark-ground renders.
   ----------------------------------------------------------------------------
   The worn shots are photographed on black and carry their own background. The
   default .shot plate is #EDEFF4, sampled from the light product renders, and
   putting that behind a black photograph draws a pale border around it that
   reads as a mistake. These get the photograph's own ground instead, and the
   caption strip inverts so the label stays legible on it.

   The shadow also has to change: a soft dark shadow under a dark image is
   invisible, so the separation comes from a faint light rim instead. */
.shot--dark {
  background: #0A1524;
  border-color: rgba(255, 255, 255, 0.10);
  box-shadow: 0 1px 2px rgba(10, 14, 22, 0.06), 0 34px 70px -46px rgba(10, 14, 22, 0.55);
}

.shot--dark figcaption {
  border-top-color: rgba(255, 255, 255, 0.10);
  color: rgba(250, 248, 244, 0.62);
}

/* ------------------------------------------------------- hover swap -- */

/* Product shot at rest, the same necklace worn on hover. Oura's store page
   does this and it works for a reason: the cut-out sells the object, the worn
   shot answers "what does it look like on me", and you get both without
   spending a second image slot in the grid.

   The two photographs are on OPPOSITE grounds — the render is on white, the
   worn shot on black — so the frame and the caption have to cross-fade with
   them. Fading only the image leaves a white plate showing through a dark
   photograph for half a second, which reads as a broken image rather than as
   a transition. All three properties share one duration for that reason.

   Both source images are already 4:5 (1122x1402 and 952x1190), so nothing is
   cropped, rescaled or retouched — a hard rule on this project. If a future
   render arrives at another ratio, re-cut it to 4:5 BEFORE it goes in here
   rather than letting object-fit paper over it. */

/* The frame stays white. It used to flip to #0A1524 on hover to sit under the
   dark worn photograph, and that caused two problems for no benefit:

   1. The product shot underneath is fully opaque and the worn shot covers the
      frame edge to edge, so the plate is never actually visible behind either
      one. The colour change was doing nothing except during the crossfade.
   2. .shot has a 26px radius and overflow:hidden. A white caption strip inside
      a dark card leaves dark wedges in the two bottom corners, which reads as
      the card being clipped.

   Only the shadow lifts now, which is enough to say "this is interactive". */
/* position:relative is load-bearing twice over: it is the containing block for
   the worn shot (below) AND for the hint pill (further down). Without it both
   resolved against the nearest positioned ancestor — the <section> — which put
   all three pills in a stack at the top of the section instead of one on each
   card. */
.shot--swap {
  position: relative;
  background: #FFFFFF;
  border-color: var(--hairline);
  transition: box-shadow 0.55s var(--ease);
}

.shot--swap:hover,
.shot--swap.is-swapped {
  box-shadow: 0 1px 2px rgba(10,14,22,0.06), 0 34px 70px -46px rgba(10,14,22,0.55);
}

.shot--swap img { display: block; width: 100%; height: auto; }

/* The worn shot covers the WHOLE figure — photograph and caption strip both.
   That is the point: on hover the card becomes one uninterrupted photograph,
   and the finish name comes back when the cursor leaves.

   It used to be nested in a wrapper that stopped at the bottom of the product
   shot, so the caption stayed visible underneath. Flattening the markup (the
   worn <img> is now a direct child of the <figure>) is what lets inset:0 reach
   the full card height.

   `.shot--swap img` above sets height:auto at (0,1,1). This has to out-specify
   it or the worn shot renders at its own ratio and leaves a band of bare plate
   under any image that is not exactly 4:5 — precisely how the gold shot
   arrived. `.shot--swap img.swap__on` is (0,2,1) for that reason.

   The box it covers is taller than 4:5 by the height of the caption, so cover
   crops the left and right edges by a few percent and keeps every pixel of the
   vertical. The necklace is horizontally centred in all three photographs, so
   it stays centred and nothing that matters is lost. */
.shot--swap img.swap__on {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 3;
  opacity: 0;
  transition: opacity 0.55s var(--ease);
}

.shot--swap:hover .swap__on,
.shot--swap.is-swapped .swap__on { opacity: 1; }

/* The caption does NOT change colour, and that is deliberate.

   It used to: the strip faded white -> black while the text faded dark grey ->
   light, both over 0.55s. Halfway through they were BOTH mid-grey at the same
   instant, contrast collapsed to roughly 1:1, and the word disappeared for a
   few frames every single hover. Settled contrast was fine at either end
   (6.7:1 and 18.6:1), which is why it only showed up in motion.

   It is a fixed white strip with fixed dark text at 6.7:1, and the photograph
   simply passes over the top of it. Nothing about it animates, so there is no
   midpoint to cross. Two colours that pass through each other are always a bug
   — if a future change re-darkens this strip, snap the text first rather than
   easing both. */
/* `.shot.shot--swap` (0,2,1), not `.shot--swap` (0,1,1). The base rule
   `.shot figcaption` is also (0,1,1) and sits LATER in this file, so at equal
   specificity it won on source order and the colour below did nothing — which
   only became visible when the dark theme flipped --ink-soft to near-white and
   put light text on this hardcoded white strip at 1.9:1. Doubling the class is
   the smallest fix that survives someone moving either rule. */
.shot.shot--swap figcaption {
  background: #FFFFFF;
  /* NOT var(--ink-soft): that token is near-white now and this strip is
     hardcoded white. Pinned dark, 7.4:1 on the strip. */
  color: #4A5670;
  border-top-color: rgba(10, 14, 22, 0.07);
}

/* There was a "Hover to see it worn" pill floating over each card until
   6 August 2026, hidden once the reader had hovered any one of them. Removed
   deliberately: the reveal is discoverable enough without being announced, and
   the instruction was the only thing on this section that talked about the
   interface rather than the product.

   The tap toggle in app.js stays. Touch has no hover, so a phone reader now
   finds the worn shot by tapping rather than by being told to — which is the
   one place this costs something. */

@media (prefers-reduced-motion: reduce) {
  .shot--swap,
  .swap__on,
  .shot--swap figcaption { transition: none; }
}

/* Caption as a specimen plate label.
   ----------------------------------------------------------------------------
   These were completely unstyled — Inter at 18px in full ink, which made them
   the only element on the page written in body-copy voice. Everything else that
   names a thing rather than saying it (the eyebrows, the channel tags, the spec
   figures) is small mono uppercase, so a caption in black sans read as a
   caption someone forgot about.

   It sits inside the frame, on the strip of the render's own backdrop below the
   product, with a hairline above it — the treatment a museum or a watch
   catalogue uses. That is also why the type is quiet: the label should be
   findable, not read first. --ink-soft rather than --ink-faint because a
   finish name is content, and --ink-faint is 3.4:1 and documented decorative
   only. */
.shot figcaption {
  width: 100%;
  padding: 0.85rem 1rem 0.95rem;
  border-top: 1px solid rgba(10, 14, 22, 0.07);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  /* Tracked-out uppercase gains a trailing gap from the last letter's spacing;
     the indent pulls the optical centre back to true. */
  text-indent: 0.24em;
  text-transform: uppercase;
  text-align: center;
  color: var(--ink-soft);
  line-height: 1;
}


/* .pair is gone with the second worn grid it laid out. Its one hard-won rule
   is worth restating where the next person will need it: never put width:100%
   on a .shot img globally. .shot defaults to justify-items:center precisely so
   an image cannot be stretched past its own pixel count, and the one time that
   default was overridden across the board it upscaled the portrait shots 1.65x
   and made the whole set look cheap. .options opts in deliberately, because
   its two are cropped large enough to afford it. Re-checked after the drop to
   two columns doubled the column width: at the widest the grid ever gets, each
   renders at 528px against 952px and 908px of source, so there is still no
   upscaling and still enough pixels for a 2x display. */

/* Image beside prose. The image leads on desktop because the electrode shot
   is the single most persuasive asset on the page; on mobile the words come
   first, since a photo with no framing is a scroll-past. */
.split { display: grid; gap: clamp(2.25rem, 6vw, 4rem); align-items: center; }

@media (min-width: 62rem) {
  .split { grid-template-columns: 0.9fr 1.1fr; }
}

@media (max-width: 61.99rem) {
  .split > .shot { order: 2; }
  .split > div { order: 1; }
}


/* ------------------------------------------------------- signal traces -- */

/* Each channel card carries its OWN real signal shape, scrolling. This is the
   page's best motion: it is the product's actual output, not an effect. */
.trace {
  height: 42px;
  margin-top: 1.1rem;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent);
}

.trace svg { width: 200%; height: 100%; }

.trace path {
  fill: none;
  stroke: var(--dot, var(--signal));
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.9;
}

@media (prefers-reduced-motion: no-preference) {
  .trace svg { animation: trace-drift var(--drift, 14s) linear infinite; }
}

@keyframes trace-drift {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Hero trace — wider, quieter, the page's heartbeat. */
.hero-trace {
  height: 64px;
  margin-top: clamp(2.5rem, 6vw, 4rem);
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}

.hero-trace svg { width: 200%; height: 100%; }
.hero-trace path { fill: none; stroke: var(--signal); stroke-width: 1.5; opacity: 0.5; stroke-linecap: round; stroke-linejoin: round; }

@media (prefers-reduced-motion: no-preference) {
  .hero-trace svg { animation: trace-drift 20s linear infinite; }
}

/* ------------------------------------------------------------- channels -- */

.channels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: 1.25rem;
  margin-top: clamp(3rem, 7vw, 5rem);
}

.channel {
  background: var(--card);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 1.9rem 1.7rem 1.5rem;
  display: flex;
  flex-direction: column;
  transition: transform 0.55s var(--ease), box-shadow 0.55s var(--ease);
  box-shadow: 0 1px 2px rgba(10,14,22,0.03);
}

.channel:hover {
  transform: translateY(-4px);
  box-shadow: 0 2px 4px rgba(10,14,22,0.05), 0 22px 44px -28px rgba(10,14,22,0.3);
}

.channel__head { display: flex; align-items: center; gap: 0.65rem; margin-bottom: 0.9rem; }

/* Identity is carried by the label text as well as the colour — never colour
   alone (WCAG 1.4.1). */
.channel__dot {
  position: relative;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--dot, var(--signal));
  flex: none;
}

/* Live indicator: each channel pulses at its own rate, loosely tracking how
   fast that sensor really samples, so the grid reads as seven independent
   instruments rather than one animation played seven times. */
@media (prefers-reduced-motion: no-preference) {
  .channel__dot::after {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 1px solid var(--dot, var(--signal));
    opacity: 0;
    animation: dot-pulse var(--pulse, 2.4s) var(--ease-soft) infinite var(--pulse-delay, 0s);
  }
}

@keyframes dot-pulse {
  0% { transform: scale(0.6); opacity: 0.7; }
  70%, 100% { transform: scale(2.5); opacity: 0; }
}

.channel__label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dot, var(--ink));
}

/* Set in the display serif, matching .craft__name exactly. These were Inter at
   600 — the last bold-sans headings on the page, and the thing that made a
   channel card read like app UI rather than like the rest of this site. The
   structure is identical to a craft tile (mono tag, name, description), so
   they should be set identically.

   Weight stays 400: Instrument Serif ships at 400 only, and anything heavier
   makes the browser synthesise a bold and smear the glyphs. */
.channel__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-1);
  letter-spacing: -0.018em;
  line-height: 1.15;
  margin-bottom: 0.5rem;
}
.channel__desc { font-size: var(--step--1); color: var(--ink-soft); line-height: 1.55; }

/* Descriptions run to different lengths, which left every trace sitting at a
   different height across a row. Pushing them to the bottom of the card puts
   them on one line across the grid — the row reads as a single instrument
   panel instead of six unrelated cards. The minimum keeps the gap from
   collapsing on the shortest card. */
.channel .trace { margin-top: auto; padding-top: 1.1rem; }

/* The reference channel spans the row — no empty cell, and the different
   treatment says "this one isn't about you" without a word. */
.channel--wide {
  grid-column: 1 / -1;
  background: linear-gradient(180deg, var(--card), var(--paper-tint));
}

@media (min-width: 44rem) {
  .channel--wide { display: grid; grid-template-columns: 10rem 1fr; gap: 1.75rem; align-items: start; }
  .channel--wide .channel__head { margin-bottom: 0; margin-top: 0.15rem; }
  .channel--wide .trace { grid-column: 2; }
}

.channel--wide__body { display: grid; gap: 0.45rem; }
.channel--wide .channel__desc { max-width: 54ch; }


/* ------------------------------------------------------------- spec table -- */

/* Watch-catalogue vocabulary: mono figures, dot leaders, hairline rows. This
   is the page's proof section — with no reservations yet there is nothing to
   cite, so checkable numbers carry the credibility that testimonials would. */
.spec {
  max-width: 40rem;
  margin: clamp(3.5rem, 8vw, 5.5rem) auto 0;
  padding-top: clamp(2rem, 5vw, 3rem);
  border-top: 1px solid var(--hairline);
}

.spec__list { display: grid; gap: 0; }

.spec__row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 0.75rem;
  padding-block: 0.85rem;
  border-bottom: 1px solid var(--hairline);
}

.spec__row dt { color: var(--ink-soft); font-size: var(--step--1); }

/* The leader dots that make a spec sheet read as a spec sheet. */
.spec__row dt::after {
  content: '';
  display: inline-block;
  width: 0;
}

.spec__row dd {
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--ink);
  letter-spacing: 0.02em;
}

/* ----------------------------------------------------- app preview -- */

/* This browser is meant to be understood as one composition. Its top edge is
   tighter than the page's editorial sections so the statement, tabs, feature
   copy and preview remain visible together on a desktop screen. */
#what { padding-top: clamp(3rem, 5vw, 4.5rem); }

/* The feature browser: one large app screen, all seven listed beside it.
   Replaced the seven channel cards on 5 August 2026 — same seven things, so
   keeping both said everything twice.

   Everything is scoped under .apx. The inner class names (.uc, .row, .pill)
   are deliberately generic because they describe app UI, and scoping is what
   stops them colliding with the page's own .card / .cards.

   The list carries the real copy in the markup. If app.js never runs you still
   get all seven names and descriptions — only the phone screen is lost, which
   is illustration rather than content. */

.apx { display: grid; gap: 2.5rem; margin-top: clamp(2.5rem, 6vw, 4rem); }
@media (min-width: 58rem) { .apx { grid-template-columns: 1fr 1fr; gap: 3.5rem; align-items: start; } }
@media (min-width: 58rem) { .apx__stage { position: sticky; top: 5rem; } }

.apx__list { list-style: none; }
.apx__item {
  display: grid; grid-template-columns: auto 1fr; gap: 0.75rem;
  padding: 0.9rem 0 0.9rem 0.95rem; border-left: 2px solid var(--hairline);
  opacity: 0.45; transition: opacity 0.4s var(--ease), border-color 0.4s var(--ease);
}
.js .apx__item { cursor: pointer; }
.apx__item:hover { opacity: 0.75; }
.apx__item.is-on { opacity: 1; border-color: var(--k); }
.apx__pip { width: 7px; height: 7px; border-radius: 50%; background: var(--k); margin-top: 0.6rem; }
.apx__nm { font-family: var(--font-display); font-weight: 400; font-size: var(--step-2); letter-spacing: -0.018em; line-height: 1.2; }
.apx__ds { color: var(--ink-soft); font-size: var(--step-0); line-height: 1.5; margin-top: 0.3rem; }
/* Only collapse the descriptions once script is driving the screen — without
   it, every description stays open and the list reads as a plain feature list. */
.js .apx__ds { max-height: 0; margin-top: 0; overflow: hidden; transition: max-height 0.5s var(--ease), margin 0.5s var(--ease); }
.js .apx__item.is-on .apx__ds { max-height: 8rem; margin-top: 0.3rem; }

.apx__cap {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 1.1rem;
  text-align: center;
}

.apx__bar { height: 2px; background: var(--hairline); border-radius: 2px; overflow: hidden; margin-top: 1.5rem; }
.apx__fill { display: block; height: 100%; width: 0; background: var(--ink); }
/* .apx__note styled the mockup caption that was removed on 6 August 2026.
   Its only element is gone, so the rule went with it. */

/* ---- the phone, in the app's own tokens (src/shared/theme.ts) ---- */
.apx { --app-bg:#0B0E13; --app-surf:#151A22; --app-raised:#1C2330;
  --app-text:#F2F5F9; --app-muted:#A3AEC0; --app-faint:#7E8B9E;
  --app-line:rgba(255,255,255,0.08); --ok:#3DD68C; }

/* The phone. A faint wash of the active channel's colour sits at the top,
   under the content — the same trick a real OLED panel gives you when a bright
   accent is on screen. It is what stops seven identical dark rectangles from
   feeling like seven identical dark rectangles, and it recolours itself for
   free because --k changes with the screen. */
.apx .ph {
  position: relative;
  isolation: isolate;
  /* Not a flat fill. A real device is lit from above, so the body carries a
     vertical gradient — without it the panel reads as a coloured rectangle no
     matter how good the contents are. */
  background: linear-gradient(180deg, #10141C 0%, var(--app-bg) 34%);
  border: 1px solid var(--app-line);
  border-radius: 34px;
  padding: 0.9rem 0.9rem 1.25rem;
  color: var(--app-text);
  /* Four layers, each doing one job: a bright hairline for the machined edge,
     an inner top highlight for the glass, a tight shadow to seat it, and a
     long soft one for the drop. A single shadow always reads as either sharp
     or vague, never as an object. */
  box-shadow:
    0 0 0 1px rgba(255,255,255,0.055),
    0 1px 0 rgba(255,255,255,0.08) inset,
    0 2px 10px rgba(0,0,0,0.5),
    0 60px 120px -55px rgba(0,0,0,1);
}

.apx .ph::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 45%;
  z-index: -1;
  border-radius: 34px 34px 0 0;
  background: radial-gradient(120% 100% at 50% 0%, var(--k), transparent 70%);
  opacity: 0.14;
  transition: opacity 0.6s var(--ease);
}
.apx .ph__status { display:flex; justify-content:space-between; padding:0.35rem 0.7rem 0.6rem;
  font-family:var(--font-mono); font-size:0.56rem; color:var(--app-faint); letter-spacing:0.08em; }
.apx .ph__nav { display:flex; align-items:center; justify-content:space-between; padding:0.2rem 0.7rem 0.9rem; }
.apx .ph__ttl { font-family:var(--font-display); font-size:1.85rem; letter-spacing:-0.024em; }
.apx .ph__when { font-family:var(--font-mono); font-size:0.64rem; letter-spacing:0.16em; text-transform:uppercase; color:var(--app-faint); }
.apx .ph__body { display:grid; gap:0.7rem; padding:0 0.15rem; }

/* Inner cards get a top highlight so they read as raised surfaces rather than
   as lighter rectangles painted on the background. */
/* The cards. Previously a flat two-stop gradient with one inset line, which
   read as "dark box" rather than as a surface with light falling on it. Now a
   translucent white wash over the surface colour, a brighter top hairline, and
   a real drop — so each card sits ON the panel instead of being painted into
   it. This is most of what makes the preview look built rather than mocked. */
.apx .uc {
  position: relative;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.012) 42%),
    var(--app-surf);
  border: 1px solid var(--app-line);
  border-radius: 18px;
  padding: 1.05rem 1.1rem;
  box-shadow:
    0 1px 0 rgba(255,255,255,0.07) inset,
    0 1px 2px rgba(0,0,0,0.35),
    0 14px 30px -20px rgba(0,0,0,0.95);
}

/* A one-pixel specular line across the top edge, fading out at both ends —
   the thing that separates a real glass surface from a rounded rectangle.
   Inset so it follows the radius rather than cutting across the corners. */
.apx .uc::before {
  content: '';
  position: absolute;
  inset: 0 12% auto;
  height: 1px;
  border-radius: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.14), transparent);
  pointer-events: none;
}
.apx .uc__h { display:flex; align-items:center; justify-content:space-between; margin-bottom:0.55rem; }
.apx .uc__t { display:flex; align-items:center; gap:0.5rem; font-family:var(--font-mono); font-size:0.68rem;
  letter-spacing:0.17em; text-transform:uppercase; color:var(--app-muted); }
.apx .uc__t i { width:6px; height:6px; border-radius:50%; background:var(--k); display:inline-block; }
.apx .uc__chev { color:var(--app-faint); font-size:0.85rem; line-height:1; }
/* font-variant-numeric:tabular-nums so a figure that ticks never shifts width,
   which is the difference between a live readout and a jittering label. */
.apx .uc__big { font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:2.6rem; line-height:1; letter-spacing:-0.035em;
  font-variant-numeric: tabular-nums; }
.apx .uc__big sup { font-size:0.82rem; color:var(--app-muted); margin-left:0.25rem; }
.apx .uc__sub { font-size:0.86rem; line-height:1.45; color:var(--app-muted); margin-top:0.4rem; }

.apx .pill { font-family:var(--font-mono); font-size:0.6rem; letter-spacing:0.13em; text-transform:uppercase;
  padding:0.22rem 0.45rem; border-radius:99px; border:1px solid currentColor; }
.apx .pill--ok { color:var(--ok); } .apx .pill--k { color:var(--k); } .apx .pill--mut { color:var(--app-faint); }

.apx .row { display:flex; align-items:center; gap:0.7rem; padding:0.8rem 0; border-top:1px solid var(--app-line); }
.apx .row:first-of-type { border-top:0; }
.apx .row__ic { width:26px; height:26px; border-radius:8px; background:var(--app-raised); flex:none;
  display:flex; align-items:center; justify-content:center; font-size:0.6rem; color:var(--k); }
.apx .row__m { flex:1; min-width:0; }
.apx .row__n { font-size:0.92rem; line-height:1.35; color:var(--app-text); }
.apx .row__d { font-family:var(--font-sans); font-size:0.76rem; color:var(--app-faint); margin-top:0.2rem;
  display:flex; gap:0.5rem; flex-wrap:wrap; }
.apx .row__v { font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:1rem; color:var(--app-text); white-space:nowrap;
  font-variant-numeric: tabular-nums; }
.apx .btn2 { font-family:var(--font-sans); font-size:0.74rem; padding:0.4rem 0.7rem; border-radius:8px;
  border:1px solid var(--app-line); background:var(--app-raised); color:var(--app-muted); }

.apx .prog { height:6px; background:var(--app-raised); border-radius:4px; margin-top:0.9rem; position:relative; }
.apx .prog i { position:absolute; left:0; top:0; bottom:0; background:var(--k); border-radius:3px; }
.apx .prog b { position:absolute; top:50%; width:13px; height:13px; border-radius:50%; background:var(--app-text); box-shadow:0 0 0 3px var(--app-surf); transform:translate(-50%,-50%); }
.apx .prog__lb { display:flex; justify-content:space-between; font-family:var(--font-mono); font-size:0.64rem; color:var(--app-faint); margin-top:0.5rem; }

/* The ECG panel. Given more height, a darker well than the card around it, and
   a glow on the stroke — on the one screen that carries the page's whole
   argument, the waveform should be the brightest thing in the frame. */
.apx .ekg { background:linear-gradient(180deg, #0A0D13, #0D1119); border:1px solid rgba(255,255,255,0.05);
  border-radius:12px; padding:0.55rem; position:relative; overflow:hidden; margin-top:0.35rem; }
.apx .ekg__g { position:absolute; inset:0; background-image:linear-gradient(var(--app-line) 1px,transparent 1px),
  linear-gradient(90deg,var(--app-line) 1px,transparent 1px); background-size:13px 13px; opacity:0.55; }
.apx .ekg svg { width:100%; height:88px; display:block; position:relative; }
.apx .ekg path { fill:none; stroke:var(--k); stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--k) 55%, transparent)); }

.apx .hyp { display:grid; gap:7px; margin-top:0.2rem; }
.apx .hyp__r { display:grid; grid-template-columns:3.4rem 1fr 3.6rem; align-items:center; gap:0.6rem; }
.apx .hyp__n { font-family:var(--font-sans); font-size:0.76rem; letter-spacing:0; text-transform:none; color:var(--app-muted); }
.apx .hyp__t { height:20px; background:var(--app-raised); border-radius:5px; position:relative; overflow:hidden; }
.apx .hyp__b { position:absolute; top:0; bottom:0; background:var(--k); border-radius:4px; opacity:0.92; }
.apx .hyp__v { font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:0.76rem; color:var(--app-text); text-align:right; }
.apx .axis { display:flex; justify-content:space-between; font-family:var(--font-mono); font-size:0.62rem; color:var(--app-faint); margin-top:0.55rem; }

.apx .ln { background:linear-gradient(180deg, #0A0D13, #0D1119); border:1px solid rgba(255,255,255,0.05);
  border-radius:12px; padding:0.65rem; margin-top:0.35rem; }
.apx .ln svg { width:100%; height:72px; display:block; }
.apx .ln .l { fill:none; stroke:var(--k); stroke-width:1.7; stroke-linejoin:round;
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--k) 45%, transparent)); }
.apx .ln .a { fill:var(--k); opacity:0.13; }
.apx .ln .m { fill:var(--app-bg); stroke:var(--k); stroke-width:1.5; }
.apx .ln .base { stroke:var(--app-line); stroke-width:1; stroke-dasharray:3 4; }

.apx .rib { height:26px; border-radius:7px; background:var(--k); opacity:0.9; position:relative; overflow:hidden; margin-top:0.2rem; }
.apx .rib i { position:absolute; top:0; bottom:0; width:3px; background:var(--app-bg); }

@media (prefers-reduced-motion: reduce) { .apx__fill { display: none; } }

/* ------------------------------------------------ living app stage -- */

/* This supersedes the legacy .apx list/phone rules above. Those selectors are
   intentionally left isolated until the new section has shipped; none of the
   old list or phone classes remain in the document. */
.apx {
  --app-bg: #070D17;
  --app-surface: #0D1726;
  --app-raised: #132137;
  --app-text: #F5F8FC;
  --app-muted: #9DABC0;
  --app-faint: #66768F;
  --app-line: rgba(255,255,255,0.09);
  display: block;
  width: min(92rem, calc(100vw - (2 * var(--gutter))));
  margin-top: 0;
  margin-left: calc((100% - min(92rem, calc(100vw - (2 * var(--gutter))))) / 2);
  position: relative;
  isolation: isolate;
}

.apx::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 5rem 8% 1rem;
  background: radial-gradient(ellipse at center, color-mix(in srgb, var(--k) 8%, transparent), transparent 68%);
  filter: blur(22px);
  pointer-events: none;
}

.apx__head { text-align: center; }

.apx__cap {
  font-size: 0.68rem;
  letter-spacing: 0.24em;
  color: var(--ink-faint);
  margin-bottom: 1.1rem;
}

.apx__headline {
  max-width: 22ch;
  margin-inline: auto;
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 4vw, 4.35rem);
  font-weight: 400;
  line-height: 0.98;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.apx__categories {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  margin-top: clamp(2.4rem, 4vw, 3.4rem);
  border-bottom: 1px solid var(--hairline);
}

.apx__category {
  appearance: none;
  position: relative;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  padding: 0.62rem 0.4rem 0.78rem;
  font-family: var(--font-sans);
  font-size: clamp(0.76rem, 0.82vw, 0.88rem);
  letter-spacing: 0.055em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.3s var(--ease);
  white-space: nowrap;
}

.apx__category span {
  color: var(--ink-faint);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  margin-right: 0.45rem;
}

.apx__category::after {
  content: '';
  position: absolute;
  left: 50%;
  right: 50%;
  bottom: -1px;
  height: 2px;
  background: var(--k);
  transition: left 0.45s var(--ease), right 0.45s var(--ease);
}

.apx__category:hover,
.apx__category.is-on { color: var(--ink); }
.apx__category.is-on::after { left: 13%; right: 13%; }
.apx__category.is-on span { color: var(--k); }

.apx__scene {
  display: grid;
  grid-template-columns: minmax(15rem, 1fr) minmax(30rem, 1.25fr) minmax(15rem, 1fr);
  grid-template-rows: repeat(3, minmax(7.5rem, auto));
  gap: clamp(1rem, 2vw, 1.75rem) clamp(1.5rem, 2.7vw, 2.7rem);
  align-items: center;
  margin-top: clamp(2.25rem, 4vw, 3.25rem);
  min-height: 33rem;
}

.apx__feature-group[hidden] { display: none; }

@media (min-width: 68.01rem) {
  .apx__feature-group:not([hidden]) { display: contents; }

  /* Four Heart features sit in two balanced pairs. Pulling both pairs inward
     keeps them visually connected instead of pinning them to the stage ends. */
  [data-category-panel="heart"] .apx__feature--l1,
  [data-category-panel="heart"] .apx__feature--r1 {
    transform: translateY(1rem);
  }
  [data-category-panel="heart"] .apx__feature--l3,
  [data-category-panel="heart"] .apx__feature--r3 {
    transform: translateY(-1rem);
  }
}

.apx__feature {
  appearance: none;
  position: relative;
  z-index: 2;
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--ink-soft);
  text-align: left;
  cursor: pointer;
  opacity: 0.84;
  transition: opacity 0.35s var(--ease), color 0.35s var(--ease), transform 0.35s var(--ease);
}

.apx__feature:hover { opacity: 0.96; }
.apx__feature.is-on { color: var(--ink); opacity: 1; }
.apx__feature--l1 { grid-column: 1; grid-row: 1; }
.apx__feature--l2 { grid-column: 1; grid-row: 2; }
.apx__feature--l3 { grid-column: 1; grid-row: 3; }
.apx__feature--r1 { grid-column: 3; grid-row: 1; }
.apx__feature--r2 { grid-column: 3; grid-row: 2; }
.apx__feature--r3 { grid-column: 3; grid-row: 3; }

.apx__feature::after {
  content: '';
  position: absolute;
  top: 0.55rem;
  width: clamp(1rem, 2.4vw, 2.5rem);
  height: 1px;
  background: var(--hairline);
  transition: background 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.apx__feature[class*="--l"]::after { left: calc(100% + 0.7rem); }
.apx__feature[class*="--r"]::after { right: calc(100% + 0.7rem); }
.apx__feature.is-on::after { background: var(--k); box-shadow: 0 0 14px color-mix(in srgb, var(--k) 55%, transparent); }

.apx__idx {
  display: block;
  margin-bottom: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  color: var(--ink-faint);
}

.apx__feature.is-on .apx__idx { color: var(--k); }

.apx__feature strong {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.75vw, 2rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.018em;
}

.apx__feature > span:last-child {
  display: block;
  margin-top: 0.35rem;
  font-size: clamp(0.94rem, 0.98vw, 1.06rem);
  line-height: 1.44;
  color: var(--ink-soft);
}

.apx__stage {
  position: static;
  grid-column: 2;
  grid-row: 1 / 4;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-self: center;
  width: 100%;
  max-width: 42rem;
  min-width: 0;
}

.apx-screen {
  position: relative;
  isolation: isolate;
  width: 100%;
  height: auto;
  min-height: 0;
  overflow: hidden;
  padding: clamp(0.85rem, 1.1vw, 1.05rem);
  color: var(--app-text);
  background:
    linear-gradient(180deg, rgba(255,255,255,0.022), transparent 24%),
    radial-gradient(90% 58% at 50% 0%, color-mix(in srgb, var(--k) 11%, transparent), transparent 70%),
    var(--app-bg);
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 24px;
  box-shadow: 0 34px 90px -54px rgba(0,0,0,0.92), 0 1px 0 rgba(255,255,255,0.065) inset;
  transform-origin: center;
  animation: apx-screen-in 0.65s var(--ease) both;
}

.apx-screen::before {
  content: '';
  position: absolute;
  inset: 0 12% auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
}

@keyframes apx-screen-in {
  from { opacity: 0; transform: translateY(8px) scale(0.992); }
  to { opacity: 1; transform: none; }
}

.apx-screen__bar,
.apx-screen__title,
.ui-panel__head,
.ui-row,
.ui-axis,
.ui-calendar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.apx-screen__bar {
  padding-bottom: 0.62rem;
  border-bottom: 1px solid var(--app-line);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  color: var(--app-faint);
}

.apx-screen__signal { display: inline-flex; align-items: center; gap: 0.45rem; }
.apx-screen__signal i,
.ui-live-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--k);
  box-shadow: 0 0 12px color-mix(in srgb, var(--k) 75%, transparent);
}

.apx-screen__title { align-items: flex-end; gap: 1rem; padding: 0.72rem 0 0.65rem; }
.apx-screen__title h4 {
  margin-top: 0.25rem;
  font-family: var(--font-display);
  font-size: clamp(1.55rem, 2.15vw, 2.2rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.025em;
}

.ui-kicker,
.ui-state {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--app-faint);
}

.ui-state {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--k);
  text-align: right;
}

.apx-screen__body { display: grid; gap: 0.55rem; }

.ui-panel {
  position: relative;
  padding: clamp(0.72rem, 0.95vw, 0.9rem);
  background: linear-gradient(180deg, rgba(255,255,255,0.035), rgba(255,255,255,0.012));
  border: 1px solid var(--app-line);
  border-radius: 17px;
}

.ui-panel--flat { background: transparent; }
.ui-panel__head { gap: 1rem; margin-bottom: 0.48rem; }
.ui-panel__head strong { font-size: 0.9rem; font-weight: 500; color: var(--app-muted); }

.ui-value {
  font-family: var(--font-mono);
  font-size: clamp(1.95rem, 3.3vw, 3rem);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
}

.ui-value small { font-size: 0.92rem; letter-spacing: 0; color: var(--app-muted); margin-left: 0.35rem; }
.ui-value--word { font-family: var(--font-display); font-size: clamp(1.8rem, 3.2vw, 2.85rem); letter-spacing: -0.025em; }
.ui-note { margin-top: 0.32rem; color: var(--app-muted); font-size: 0.84rem; line-height: 1.36; }

.ui-chart {
  position: relative;
  overflow: hidden;
  height: clamp(4.25rem, 5.3vw, 5rem);
  margin-top: 0.48rem;
  border-radius: 12px;
  background-color: rgba(3,8,15,0.52);
  background-image:
    linear-gradient(var(--app-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--app-line) 1px, transparent 1px);
  background-size: 22px 22px;
}

.ui-chart svg { width: 100%; height: 100%; }
.ui-chart .ui-line {
  fill: none;
  stroke: var(--k);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--k) 48%, transparent));
  stroke-dasharray: 900;
  stroke-dashoffset: 0;
  animation: apx-line-in 1.25s var(--ease) both;
}
.ui-chart .ui-line--soft { stroke: color-mix(in srgb, var(--k) 45%, var(--app-faint)); stroke-width: 1.3; filter: none; }
.ui-chart .ui-area { fill: url(#apxArea); opacity: 0.25; }
.ui-chart .ui-baseline { stroke: var(--app-line); stroke-width: 1; stroke-dasharray: 4 5; }
.ui-chart .ui-point { fill: var(--app-bg); stroke: var(--k); stroke-width: 2; }

@keyframes apx-line-in { from { stroke-dashoffset: 900; } }

.ui-axis {
  margin-top: 0.28rem;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.06em;
  color: var(--app-faint);
}

.ui-axis--end { justify-content: flex-end; }

/* The ECG card has two modes driven by one value in app-preview.js. The
   number-only mode expands the existing reading into the visual space; the
   dormant waveform mode drops its graph back into the same structure. */
.ui-panel--ecg-number .ui-ecg-reading {
  min-height: clamp(5.4rem, 7.5vw, 6.5rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: 0.5rem;
}
.ui-panel--ecg-number .ui-value {
  font-size: clamp(3.8rem, 5.8vw, 5rem);
  line-height: 0.82;
}
.ui-panel--ecg-number .ui-value small { font-size: 1rem; }
.ui-panel--ecg-number .ui-note { margin-top: 0.55rem; }

.ui-ecg-visual { height: clamp(5.5rem, 7vw, 6.5rem); margin-top: 0.7rem; }
.ui-ecg-visual .ui-chart { height: 100%; margin-top: 0; }

.ui-summary-grid { display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid var(--app-line); margin-top: 0.48rem; }
.ui-summary-grid > div { padding: 0.45rem 0.6rem 0; border-left: 1px solid var(--app-line); }
.ui-summary-grid > div:first-child { border-left: 0; padding-left: 0; }
.ui-summary-grid span { display: block; font-size: 0.72rem; color: var(--app-faint); }
.ui-summary-grid strong { display: block; margin-top: 0.16rem; font-family: var(--font-mono); font-size: 0.9rem; font-weight: 400; }

.ui-bars { display: flex; align-items: end; gap: 3px; height: 4.25rem; margin-top: 0.5rem; }
.ui-bars i { flex: 1; min-width: 2px; height: var(--h); background: color-mix(in srgb, var(--k) 72%, transparent); border-radius: 2px 2px 0 0; animation: apx-bar-in 0.8s var(--ease) both; transform-origin: bottom; }
.ui-bars i:nth-child(3n) { background: color-mix(in srgb, var(--k) 42%, var(--app-faint)); }
@keyframes apx-bar-in { from { transform: scaleY(0); opacity: 0; } }

.ui-score-layout { display: grid; grid-template-columns: 0.75fr 1.25fr; gap: 0.8rem; align-items: center; }
.ui-panel--score { padding-bottom: 0.72rem; }
.ui-panel--score .ui-summary-grid { margin-top: 0.65rem; }
.ui-score-note { margin: 0 0 0.55rem; }
.ui-ring {
  --score: 88;
  width: min(6.75rem, 100%);
  aspect-ratio: 1;
  margin-inline: auto;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: conic-gradient(var(--k) calc(var(--score) * 1%), rgba(255,255,255,0.08) 0);
  position: relative;
}
.ui-ring::after { content: ''; position: absolute; inset: 9px; border-radius: 50%; background: var(--app-bg); }
.ui-ring__value { position: relative; z-index: 1; text-align: center; font-family: var(--font-mono); font-size: 2.3rem; line-height: 1; }
.ui-ring__value small { display: block; margin-top: 0.28rem; font-family: var(--font-sans); font-size: 0.58rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--app-faint); white-space: nowrap; }

.ui-contributors { display: grid; gap: 0.38rem; }
.ui-contributor { display: grid; grid-template-columns: 5.6rem 1fr 2.5rem; gap: 0.65rem; align-items: center; font-size: 0.78rem; color: var(--app-muted); }
.ui-contributor i { height: 3px; border-radius: 3px; background: var(--app-raised); overflow: hidden; }
.ui-contributor i::after { content: ''; display: block; width: var(--w); height: 100%; background: var(--k); }
.ui-contributor b { font-family: var(--font-mono); font-size: 0.74rem; font-weight: 400; text-align: right; color: var(--app-text); }

.ui-stage-stack { display: grid; gap: 0.28rem; }
.ui-stage-row { display: grid; grid-template-columns: 3.3rem 1fr 3.3rem; gap: 0.7rem; align-items: center; font-size: 0.78rem; color: var(--app-muted); }
.ui-stage-track { height: 0.85rem; border-radius: 4px; background: var(--app-raised); overflow: hidden; }
.ui-stage-track i { display: block; height: 100%; width: var(--w); background: color-mix(in srgb, var(--k) var(--o), transparent); border-radius: inherit; transform-origin: left; animation: apx-stage-in 0.9s var(--ease) both; }
.ui-stage-row b { font-family: var(--font-mono); font-size: 0.74rem; font-weight: 400; text-align: right; color: var(--app-text); }
@keyframes apx-stage-in { from { transform: scaleX(0); } }

.ui-position-timeline {
  display: flex;
  align-items: stretch;
  gap: 2px;
  height: clamp(3.1rem, 4.5vw, 3.8rem);
  margin-top: 1.1rem;
  padding: 0.25rem;
  overflow: hidden;
  border-radius: 14px;
  background: rgba(3,8,15,0.64);
}

.ui-position-segment {
  flex: var(--w) 1 0%;
  min-width: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 10px;
  color: var(--app-text);
  transform-origin: left;
  animation: apx-position-in 0.75s var(--ease) both;
}

.ui-position-segment--left { background: color-mix(in srgb, var(--k) 82%, var(--app-raised)); }
.ui-position-segment--right { background: color-mix(in srgb, var(--k) 50%, var(--app-raised)); }
.ui-position-segment--back { background: color-mix(in srgb, var(--k) 18%, var(--app-raised)); }
.ui-position-segment b {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.08em;
}

@keyframes apx-position-in {
  from { opacity: 0; transform: scaleX(0.15); }
}

.ui-panel--position { padding: clamp(0.9rem, 1.35vw, 1.2rem); }
.ui-position-hero { display: flex; align-items: end; justify-content: space-between; gap: 2rem; }
.ui-position-hero > div:first-child > span,
.ui-position-total span,
.ui-position-insight span { display: block; color: var(--app-faint); font-size: 0.72rem; letter-spacing: 0.04em; }
.ui-position-hero > div:first-child > strong {
  display: block;
  margin-top: 0.2rem;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 5vw, 4rem);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: -0.035em;
}
.ui-position-total { text-align: right; }
.ui-position-total strong { display: block; font-family: var(--font-mono); font-size: 1.25rem; font-weight: 400; }
.ui-position-total span { margin-top: 0.15rem; }
.ui-position-times { display: flex; justify-content: space-between; margin-top: 0.38rem; color: var(--app-faint); font-family: var(--font-mono); font-size: 0.65rem; }
.ui-position-breakdown { display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 0.85rem; border-top: 1px solid var(--app-line); border-bottom: 1px solid var(--app-line); }
.ui-position-breakdown > div { display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 0.45rem; padding: 0.65rem 0.75rem; border-left: 1px solid var(--app-line); }
.ui-position-breakdown > div:first-child { padding-left: 0; border-left: 0; }
.ui-position-breakdown i { width: 0.48rem; height: 0.48rem; margin-top: 0.25rem; border-radius: 50%; }
.ui-position-breakdown i.is-left { background: color-mix(in srgb, var(--k) 82%, var(--app-raised)); }
.ui-position-breakdown i.is-right { background: color-mix(in srgb, var(--k) 50%, var(--app-raised)); }
.ui-position-breakdown i.is-back { background: color-mix(in srgb, var(--k) 18%, var(--app-raised)); }
.ui-position-breakdown span { color: var(--app-faint); font-size: 0.72rem; }
.ui-position-breakdown strong { grid-column: 2; font-family: var(--font-mono); font-size: 0.92rem; font-weight: 400; }
.ui-position-insight { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; margin-top: 0.85rem; padding: 0.85rem 1rem; overflow: hidden; border-radius: 13px; background: color-mix(in srgb, var(--k) 8%, rgba(255,255,255,0.018)); }
.ui-position-insight::before { content: ''; position: absolute; inset: 0 auto 0 0; width: 2px; background: var(--k); }
.ui-position-insight strong { display: block; margin-top: 0.2rem; color: var(--app-text); font-size: 0.86rem; font-weight: 500; line-height: 1.3; }
.ui-position-insight > b { flex: none; font-family: var(--font-mono); font-size: 1.05rem; font-weight: 400; color: var(--k); }

.ui-list { display: grid; }
.ui-heart-rate-row { margin-top: 0.42rem; }
.ui-heart-rate-row .ui-row { padding-bottom: 0; }
.ui-row { gap: 0.75rem; padding: 0.4rem 0; border-top: 1px solid var(--app-line); }
.ui-row:first-child { border-top: 0; }
.ui-row__mark { width: 1.9rem; height: 1.9rem; flex: none; border-radius: 50%; display: grid; place-items: center; background: color-mix(in srgb, var(--k) 13%, transparent); color: var(--k); font-size: 0.76rem; }
.ui-row__copy { flex: 1; min-width: 0; }
.ui-row__copy strong { display: block; font-size: 0.88rem; font-weight: 500; }
.ui-row__copy span { display: block; margin-top: 0.18rem; font-size: 0.76rem; color: var(--app-faint); }
.ui-row__value { min-width: max-content; font-family: var(--font-mono); font-size: 0.88rem; color: var(--app-text); text-align: right; white-space: nowrap; }

.ui-band { position: relative; height: 0.55rem; margin: 0.55rem 0 0.38rem; border-radius: 99px; background: linear-gradient(90deg, #EF8A70, var(--k) 48%, #72B7E8); }
.ui-band::before { content: ''; position: absolute; left: var(--x); top: 50%; width: 1rem; height: 1rem; border-radius: 50%; background: var(--app-text); border: 4px solid var(--app-bg); transform: translate(-50%, -50%); box-shadow: 0 0 0 1px var(--k); }
.ui-band-labels { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 0.64rem; color: var(--app-faint); }

.ui-calendar { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.15rem; margin-top: 0.45rem; }
.ui-calendar__head { grid-column: 1 / -1; margin-bottom: 0.18rem; font-size: 0.76rem; color: var(--app-muted); }
.ui-day { height: 1.38rem; border-radius: 50%; display: grid; place-items: center; font-family: var(--font-mono); font-size: 0.62rem; color: var(--app-muted); }
.ui-day.is-muted { color: var(--app-faint); opacity: 0.45; }
.ui-day.is-range { background: color-mix(in srgb, var(--k) 15%, transparent); color: var(--app-text); }
.ui-day.is-today { background: var(--k); color: var(--app-bg); }

.ui-goal { display: grid; gap: 0.7rem; }
.ui-goal__track { height: 4px; border-radius: 4px; background: var(--app-raised); position: relative; }
.ui-goal__track i { display: block; width: var(--w); height: 100%; border-radius: inherit; background: var(--k); }
.ui-goal__track b { position: absolute; left: var(--w); top: 50%; width: 12px; height: 12px; border-radius: 50%; background: var(--app-text); border: 3px solid var(--app-bg); transform: translate(-50%, -50%); }

/* ------------------------------------------------ premium preview system --
   Every feature screen follows the same quiet hierarchy: one takeaway, one
   visualization, one layer of evidence. The components below replace the
   generic dashboard treatment without making the twenty previews identical. */
.ui-panel--premium {
  padding: clamp(0.95rem, 1.35vw, 1.2rem);
  border-color: rgba(255,255,255,0.085);
  background:
    radial-gradient(85% 120% at 0 0, color-mix(in srgb, var(--k) 7%, transparent), transparent 58%),
    linear-gradient(180deg, rgba(255,255,255,0.032), rgba(255,255,255,0.012));
  box-shadow: 0 1px 0 rgba(255,255,255,0.035) inset;
}

.ui-premium-head,
.ui-age-hero,
.ui-live-response,
.ui-insight,
.ui-goal-progress {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.ui-premium-head { margin-bottom: 0.8rem; color: var(--app-faint); font-size: 0.76rem; }
.ui-premium-head > strong { display: inline-flex; align-items: center; gap: 0.45rem; color: var(--k); font-size: 0.68rem; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; }

.ui-hero { min-width: 0; }
.ui-hero__label { display: block; color: var(--app-faint); font-size: 0.72rem; letter-spacing: 0.035em; }
.ui-hero__value {
  margin-top: 0.16rem;
  font-family: var(--font-sans);
  font-size: clamp(2.6rem, 5.6vw, 4.65rem);
  font-weight: 300;
  line-height: 0.98;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
  text-wrap: balance;
}
.ui-hero__value small { margin-left: 0.45rem; color: var(--app-muted); font-size: 0.88rem; font-weight: 400; letter-spacing: 0; }
.ui-hero > p { max-width: 34rem; margin-top: 0.38rem; color: var(--app-muted); font-size: 0.84rem; line-height: 1.38; }

.ui-panel--premium .ui-chart {
  height: clamp(5rem, 6.2vw, 5.8rem);
  margin-top: 0.9rem;
  border: 1px solid rgba(255,255,255,0.045);
  background: rgba(3,8,15,0.5);
}
.ui-panel--premium .ui-summary-grid { margin-top: 0.75rem; }
.ui-panel--premium .ui-summary-grid > div { padding-top: 0.58rem; }
.ui-panel--premium .ui-summary-grid strong { font-family: var(--font-sans); font-size: 0.9rem; font-weight: 500; letter-spacing: -0.015em; }

.ui-metric-pair { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 1.15rem; }
.ui-metric-pair > div { min-width: 0; }
.ui-metric-pair > div + div { padding-left: 1.15rem; border-left: 1px solid var(--app-line); }
.ui-metric-pair > div + div .ui-hero__value { font-size: clamp(2.2rem, 4vw, 3.35rem); }

.ui-age-hero { align-items: end; }
.ui-age-hero > .ui-hero { flex: 1; }
.ui-age-hero > div:last-child { min-width: 6.4rem; padding: 0.75rem 0.9rem; text-align: right; border-radius: 14px; background: rgba(255,255,255,0.03); }
.ui-age-hero > div:last-child span { display: block; color: var(--app-faint); font-size: 0.7rem; }
.ui-age-hero > div:last-child strong { display: block; margin-top: 0.15rem; font-size: 1.8rem; font-weight: 400; letter-spacing: -0.04em; }
.ui-age-scale { margin-top: 1.15rem; }
.ui-age-scale__track { position: relative; height: 0.38rem; border-radius: 99px; background: linear-gradient(90deg, color-mix(in srgb, var(--k) 76%, transparent), color-mix(in srgb, var(--k) 22%, var(--app-raised))); }
.ui-age-scale__track i,
.ui-age-scale__track b { position: absolute; top: 50%; width: 0.9rem; height: 0.9rem; border-radius: 50%; transform: translate(-50%, -50%); }
.ui-age-scale__track i { left: var(--value); background: var(--k); box-shadow: 0 0 0 4px color-mix(in srgb, var(--k) 14%, transparent); }
.ui-age-scale__track b { left: var(--actual); background: var(--app-text); border: 3px solid var(--app-bg); }
.ui-age-scale__labels { display: flex; justify-content: space-between; margin-top: 0.45rem; color: var(--app-faint); font-family: var(--font-mono); font-size: 0.62rem; }

.ui-insight { position: relative; margin-top: 0.85rem; padding: 0.78rem 0.9rem; overflow: hidden; border-radius: 13px; background: color-mix(in srgb, var(--k) 7%, rgba(255,255,255,0.018)); }
.ui-insight::before { content: ''; position: absolute; inset: 0 auto 0 0; width: 2px; background: var(--k); }
.ui-insight span { display: block; color: var(--app-faint); font-size: 0.68rem; }
.ui-insight strong { display: block; max-width: 30rem; margin-top: 0.16rem; color: var(--app-text); font-size: 0.83rem; font-weight: 500; line-height: 1.32; }
.ui-insight > b { flex: none; color: var(--k); font-family: var(--font-sans); font-size: 0.86rem; font-weight: 500; text-align: right; }

.ui-panel--score .ui-ring { width: min(7.5rem, 100%); }
.ui-score-verdict { max-width: 21rem; margin: 0.28rem 0 0.65rem; font-size: clamp(1.15rem, 1.9vw, 1.5rem); font-weight: 500; line-height: 1.18; letter-spacing: -0.025em; }

.ui-sleep-ribbon { display: flex; gap: 2px; height: 4.1rem; margin-top: 1rem; padding: 0.25rem; border-radius: 14px; background: rgba(3,8,15,0.62); }
.ui-sleep-ribbon__segment { flex: var(--w) 1 0%; min-width: 0; display: grid; place-items: center; border-radius: 10px; }
.ui-sleep-ribbon__segment b { font-size: 0.6rem; font-weight: 500; }
.ui-sleep-ribbon__segment.is-compact { min-width: 3.25rem; }
.ui-sleep-ribbon__segment.is-compact b { font-size: 0.5rem; letter-spacing: -0.015em; }
.ui-sleep-ribbon__segment.is-light { background: color-mix(in srgb, var(--k) 36%, var(--app-raised)); }
.ui-sleep-ribbon__segment.is-deep { background: color-mix(in srgb, var(--k) 88%, var(--app-raised)); }
.ui-sleep-ribbon__segment.is-rem { background: color-mix(in srgb, var(--k) 60%, var(--app-raised)); }
.ui-sleep-ribbon__segment.is-awake { background: rgba(255,255,255,0.12); }
.ui-stage-breakdown { display: grid; grid-template-columns: repeat(4, 1fr); margin-top: 0.8rem; border-top: 1px solid var(--app-line); }
.ui-stage-breakdown > div { display: grid; grid-template-columns: auto 1fr; gap: 0.08rem 0.38rem; padding: 0.65rem 0.55rem 0; border-left: 1px solid var(--app-line); }
.ui-stage-breakdown > div:first-child { padding-left: 0; border-left: 0; }
.ui-stage-breakdown i { width: 0.42rem; height: 0.42rem; margin-top: 0.25rem; border-radius: 50%; }
.ui-stage-breakdown i.is-light { background: color-mix(in srgb, var(--k) 36%, var(--app-raised)); }
.ui-stage-breakdown i.is-deep { background: color-mix(in srgb, var(--k) 88%, var(--app-raised)); }
.ui-stage-breakdown i.is-rem { background: color-mix(in srgb, var(--k) 60%, var(--app-raised)); }
.ui-stage-breakdown i.is-awake { background: rgba(255,255,255,0.24); }
.ui-stage-breakdown span { color: var(--app-faint); font-size: 0.68rem; }
.ui-stage-breakdown strong { grid-column: 2; font-size: 0.82rem; font-weight: 500; }

.ui-signal-list { margin-top: 0.65rem; border-top: 1px solid var(--app-line); border-bottom: 1px solid var(--app-line); }

.ui-panel--illness .ui-hero__value {
  font-size: clamp(2.35rem, 4.2vw, 3.25rem);
  letter-spacing: -0.045em;
  white-space: nowrap;
}

.ui-panel--illness .ui-hero > p { margin-top: 0.25rem; }
.ui-panel--illness .ui-signal-list { margin-top: 0.45rem; }
.ui-panel--illness .ui-row { padding-block: 0.3rem; }
.ui-panel--illness .ui-insight { margin-top: 0.6rem; padding-block: 0.65rem; }

.ui-panel--hydration .ui-hero__value {
  font-size: clamp(2.35rem, 4.2vw, 3.25rem);
  letter-spacing: -0.045em;
}

.ui-panel--period .ui-hero__value {
  font-size: clamp(2.35rem, 4.2vw, 3.25rem);
  letter-spacing: -0.045em;
  white-space: nowrap;
}

.ui-panel--period .ui-calendar {
  margin-top: 0.6rem;
  gap: 0.16rem;
}

.ui-panel--period .ui-day { height: 1.35rem; }
.ui-panel--period .ui-insight { margin-top: 0.6rem; padding-block: 0.65rem; }

.ui-live-response { align-items: end; }
.ui-live-response > div { position: relative; padding-left: 1rem; }
.ui-live-response > div > i { position: absolute; left: 0; top: 0.34rem; }
.ui-live-response span { display: block; color: var(--app-faint); font-size: 0.7rem; }
.ui-live-response strong { display: block; margin-top: 0.18rem; font-size: clamp(1.35rem, 2.4vw, 2rem); font-weight: 500; letter-spacing: -0.03em; }
.ui-live-response > b { color: var(--k); font-family: var(--font-sans); font-size: 1rem; font-weight: 500; }
.ui-panel--premium .ui-bars { height: 5.25rem; margin-top: 1rem; gap: 4px; }
.ui-panel--premium .ui-bars i { border-radius: 99px; background: linear-gradient(180deg, var(--k), color-mix(in srgb, var(--k) 32%, transparent)); }

.ui-events { display: grid; }
.ui-event { display: grid; grid-template-columns: 2.8rem 2rem 1fr auto; gap: 0.7rem; align-items: center; padding: 0.7rem 0; border-top: 1px solid var(--app-line); }
.ui-event:first-child { border-top: 0; padding-top: 0; }
.ui-event__time { color: var(--app-faint); font-family: var(--font-mono); font-size: 0.68rem; }
.ui-event > i { width: 1.9rem; height: 1.9rem; display: grid; place-items: center; border-radius: 50%; background: color-mix(in srgb, var(--k) 12%, transparent); color: var(--k); font-size: 0.7rem; font-style: normal; }
.ui-event > div strong { display: block; font-size: 0.87rem; font-weight: 500; }
.ui-event > div span { display: block; margin-top: 0.12rem; color: var(--app-faint); font-size: 0.72rem; }
.ui-event > b { color: var(--app-muted); font-size: 0.72rem; font-weight: 500; }

.ui-choice-row { display: flex; gap: 0.35rem; margin-bottom: 0.9rem; }
.ui-choice-row span { padding: 0.4rem 0.7rem; border: 1px solid var(--app-line); border-radius: 99px; color: var(--app-faint); font-size: 0.68rem; }
.ui-choice-row span.is-on { border-color: color-mix(in srgb, var(--k) 50%, transparent); background: color-mix(in srgb, var(--k) 10%, transparent); color: var(--app-text); }
.ui-panel--premium .ui-goal { margin-top: 1.15rem; }
.ui-panel--premium .ui-goal__track { height: 0.48rem; }
.ui-goal-progress { margin-top: 0.55rem; color: var(--app-faint); font-size: 0.7rem; }
.ui-goal-progress strong { color: var(--app-muted); font-weight: 500; }

.ui-cycle-track { display: grid; grid-template-columns: 1fr 1.7fr 0.8fr 1.5fr; gap: 3px; margin-top: 1.1rem; }
.ui-cycle-track > div { position: relative; min-width: 0; }
.ui-cycle-track > div > span { display: block; height: 0.65rem; border-radius: 99px; background: color-mix(in srgb, var(--k) 18%, var(--app-raised)); }
.ui-cycle-track > div > span.is-follicular { background: color-mix(in srgb, var(--k) 32%, var(--app-raised)); }
.ui-cycle-track > div > span.is-ovulation { background: color-mix(in srgb, var(--k) 52%, var(--app-raised)); }
.ui-cycle-track > div > span.is-luteal { background: color-mix(in srgb, var(--k) 78%, var(--app-raised)); }
.ui-cycle-track b { display: block; margin-top: 0.45rem; color: var(--app-faint); font-size: 0.62rem; font-weight: 400; }
.ui-cycle-track .is-current::before { content: ''; position: absolute; top: -0.2rem; left: 58%; width: 1.05rem; height: 1.05rem; z-index: 2; border: 3px solid var(--app-bg); border-radius: 50%; background: var(--k); transform: translateX(-50%); box-shadow: 0 0 0 1px var(--k); }
.ui-cycle-track i { position: absolute; top: -1.55rem; left: 58%; color: var(--k); font-family: var(--font-mono); font-size: 0.58rem; font-style: normal; transform: translateX(-50%); white-space: nowrap; }
.ui-panel--premium .ui-calendar { margin-top: 0.9rem; gap: 0.25rem; }
.ui-panel--premium .ui-day { height: 1.7rem; }

@media (max-width: 68rem) {
  .apx { width: min(100%, calc(100vw - (2 * var(--gutter)))); }
  .apx__headline { max-width: 14ch; }
  .apx__categories { overflow-x: auto; grid-template-columns: repeat(7, max-content); justify-content: start; scrollbar-width: none; }
  .apx__categories::-webkit-scrollbar { display: none; }
  .apx__category { padding-inline: 1rem; }
  .apx__scene { display: flex; flex-direction: column; min-height: 0; gap: 1.6rem; align-items: stretch; }
  .apx__feature-group:not([hidden]) {
    display: flex;
    gap: 1rem;
    order: 1;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
  }
  .apx__feature-group::-webkit-scrollbar { display: none; }
  .apx__feature {
    flex: 0 0 min(20rem, 78vw);
    min-height: 10.75rem;
    padding: 1.15rem;
    border: 1px solid var(--hairline);
    border-radius: 16px;
    scroll-snap-align: start;
    background: rgba(255,255,255,0.018);
    opacity: 0.9;
  }
  .apx__feature.is-on { border-color: color-mix(in srgb, var(--k) 58%, transparent); background: color-mix(in srgb, var(--k) 6%, transparent); }
  .apx__feature::after { display: none; }
  .apx__stage { order: 2; width: 100%; max-width: 40rem; margin-inline: auto; }
  .apx-screen { height: auto; min-height: 24rem; }
}

@media (max-width: 34rem) {
  .apx__headline { font-size: clamp(2.25rem, 12vw, 3.5rem); }
  .apx-screen { min-height: 24rem; padding: 0.9rem; border-radius: 19px; }
  .apx-screen__title { align-items: flex-start; }
  .ui-state { max-width: 8rem; }
  .ui-hero__value { font-size: clamp(2.15rem, 12vw, 3.2rem); }
  .ui-hero__value small { display: inline-block; margin-left: 0.3rem; font-size: 0.72rem; }
  .ui-metric-pair { grid-template-columns: 1fr 1fr; gap: 0.7rem; }
  .ui-metric-pair > div + div { padding-left: 0.7rem; }
  .ui-metric-pair > div + div .ui-hero__value { font-size: 2.15rem; }
  .ui-age-hero { align-items: end; gap: 0.7rem; }
  .ui-age-hero > div:last-child { min-width: 5rem; padding: 0.55rem 0.65rem; }
  .ui-panel--score .ui-ring { width: 6.5rem; }
  .ui-score-verdict { font-size: 1.08rem; }
  .ui-stage-breakdown { grid-template-columns: repeat(2, 1fr); }
  .ui-stage-breakdown > div:nth-child(3) { padding-left: 0; border-left: 0; }
  .ui-stage-breakdown > div:nth-child(n+3) { padding-top: 0.55rem; }
  .ui-insight { align-items: flex-start; gap: 0.75rem; }
  .ui-event { grid-template-columns: 2.35rem 1.75rem 1fr; gap: 0.5rem; }
  .ui-event > b { grid-column: 3; }
  .ui-position-hero { align-items: flex-start; gap: 1rem; }
  .ui-position-hero > div:first-child > strong { font-size: 2.5rem; }
  .ui-position-breakdown > div { padding-inline: 0.38rem; }
  .ui-position-insight { align-items: flex-start; gap: 0.75rem; }
  .ui-choice-row { overflow-x: auto; scrollbar-width: none; }
  .ui-choice-row span { white-space: nowrap; }
  .ui-cycle-track b { font-size: 0.54rem; }
  .ui-score-layout { grid-template-columns: 1fr; }
  .ui-ring { width: 7rem; }
  .ui-chart { height: 5.5rem; }
  .ui-ecg-visual { height: 5.5rem; }
  .ui-panel--ecg-number .ui-ecg-reading { min-height: 7rem; }
  .ui-panel--ecg-number .ui-value { font-size: clamp(4.5rem, 21vw, 5.6rem); }
  .ui-summary-grid strong { font-size: 0.76rem; }
}

@media (prefers-reduced-motion: reduce) {
  .apx-screen,
  .ui-chart .ui-line,
  .ui-bars i,
  .ui-stage-track i,
  .ui-position-segment { animation: none; }
}

/* ---------------------------------------------------------------- craft -- */

/* A full visual chapter separates the physical necklace from the interactive
   health-feature browser above it. The deeper ground and full section spacing
   make the transition intentional without adding a decorative divider. */
.object-chapter {
  overflow: hidden;
  border-block: 1px solid rgba(255,255,255,0.07);
  background:
    radial-gradient(ellipse 72% 65% at 50% 15%, rgba(38,66,106,0.2), transparent 72%),
    var(--paper-deep);
}

.object-chapter .wrap { position: relative; }

/* The object, sold as an object. This replaced the nine-row spec table on
   5 August 2026 — see the note in index.html for why.

   The tiles are given a faint metallic gradient rather than a flat fill, and a
   specular highlight sweeps across each one on a long stagger. That sweep is
   the whole idea: it is the same gesture the CTA uses, and on a page selling a
   polished steel object it reads as light moving over metal rather than as a
   web effect. Slow and narrow on purpose — roughly two seconds of travel in
   every seven, so it registers without ever demanding attention. */

.craft { margin-top: 0; }

.craft__head {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-2);
  letter-spacing: -0.026em;
  line-height: 1.1;
  margin: 1.1rem 0 1rem;
  max-width: 19ch;
}

.craft__subhead {
  max-width: 44rem;
  font-size: var(--step-1);
  line-height: 1.35;
  color: var(--ink);
}

.craft__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(0.9rem, 2vw, 1.2rem);
  margin-top: clamp(2rem, 4vw, 3rem);
}

@media (min-width: 40rem) { .craft__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 68rem) { .craft__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.craft__tile {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding: clamp(1.35rem, 2.6vw, 1.9rem);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  /* Off-axis gradient so the surface has a direction to catch light on. */
  background: linear-gradient(155deg, #16273F 0%, #1D3151 46%, #12203A 100%);
  transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease), border-color 0.5s var(--ease);
}

.craft__tile:hover {
  transform: translateY(-4px);
  border-color: var(--accent-dim);
  box-shadow: 0 2px 6px rgba(10,14,22,0.05), 0 26px 50px -28px rgba(10,14,22,0.42);
}

/* The travelling highlight. Inset negative so the band is already off-canvas
   at both ends and never shows a hard edge entering or leaving. */
.craft__tile::after {
  content: '';
  position: absolute;
  inset: -50% -30%;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(104deg,
    transparent 40%,
    rgba(255, 255, 255, 0.9) 50%,
    transparent 60%);
  transform: translateX(-130%);
}

.craft__idx {
  display: block;
  font-size: 0.66rem;
  letter-spacing: 0.24em;
  color: var(--accent);
  margin-bottom: 1.1rem;
}

.craft__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-1);
  letter-spacing: -0.018em;
  line-height: 1.15;
  margin-bottom: 0.55rem;
}

.craft__desc {
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* One precision anchor kept back from the deleted table, so dropping the specs
   does not also drop the credibility they were carrying. */
.craft__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem clamp(1.6rem, 4vw, 3rem);
  margin-top: clamp(1.8rem, 3vw, 2.4rem);
  padding-top: 1.4rem;
  border-top: 1px solid var(--hairline);
  font-size: 0.76rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.craft__stats b {
  font-weight: 400;
  color: var(--signal);
  font-size: 1.15rem;
  letter-spacing: 0;
  margin-right: 0.42rem;
}

@media (prefers-reduced-motion: no-preference) {
  .craft__tile::after {
    animation: craft-sheen 7s var(--ease-soft) infinite;
    animation-delay: var(--sheen-delay, 0s);
  }
  /* Sweeps in ~2s, then rests for 5. A highlight that never stops moving
     stops reading as light and starts reading as a loading bar. */
  @keyframes craft-sheen {
    0%   { transform: translateX(-130%); }
    28%  { transform: translateX(130%); }
    100% { transform: translateX(130%); }
  }
}

.spec__note {
  margin-top: 1.5rem;
  font-size: var(--step--1);
  color: var(--ink-soft);
  line-height: 1.6;
}


/* ---------------------------------------------------------- restored -- */
/* .statement, .band* and .reserve__caveat were destroyed on 4 August 2026 by
   a scripted deletion that was meant to remove only the rhythm-curve styles.
   It cut from the rhythm comment header to the next selector it recognised
   and swallowed everything in between — including the dark band, which is the
   page's one visual peak. Recovered verbatim from git.

   The .honesty* rules that were in the same range are deliberately NOT back:
   the status plate was removed from the markup, so those are genuinely dead.

   Lesson worth keeping: delete CSS by selector, never by line range. */

/* Full-bleed and deep — the instrument panel showing through the porcelain.
   Deliberately taller than it needs to be: the pause is the point. */
.band {
  position: relative;
  background: #060E1B;
  color: var(--ink);
  padding-block: clamp(7rem, 17vw, 14rem);
  text-align: center;
  overflow: hidden;
}

.band__eyebrow {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(250, 248, 244, 0.42);
  margin-bottom: clamp(2rem, 5vw, 3.25rem);
}

/* the document outline for no reader benefit. */
.band__line {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.1rem, 6vw, 4.1rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
  max-width: 20ch;
  margin-inline: auto;
  text-wrap: balance;
}

.band__line em {
  font-style: italic;
  /* Lifted off the dark ground — the bronze accent goes muddy at this size on
     near-black, so the band gets a warmer, lighter tint of the same hue. */
  color: #9DBBE8;
}

.band__note {
  margin-top: clamp(2.25rem, 5vw, 3.25rem);
  font-size: var(--step-0);
  color: rgba(242, 246, 252, 0.62);
  max-width: 34ch;
  margin-inline: auto;
}

/* The dark band sits between two light sections; a hairline at each edge in
   the signal colour keeps the transition intentional rather than abrupt. */
.band::before,
.band::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--signal), transparent);
  opacity: 0.55;
}

.band::before { top: 0; }

.band::after { bottom: 0; }

/* under the button. */
.reserve__caveat {
  max-width: 34rem;
  margin: clamp(2rem, 5vw, 2.75rem) auto clamp(1.75rem, 4vw, 2.25rem);
  padding-top: clamp(1.5rem, 4vw, 2rem);
  border-top: 1px solid var(--hairline);
  font-size: var(--step--1);
  line-height: 1.6;
  color: var(--ink-soft);
  text-align: center;
}

.statement { max-width: 44rem; margin-inline: auto; text-align: center; }

.statement h2 { margin-bottom: 1.5rem; }

.statement p { color: var(--ink-soft); font-size: var(--step-1); line-height: 1.6; }

/* ------------------------------------------------------ band spotlight -- */

/* The dark band is the page's one peak, and it was a flat rectangle. A soft
   pool of light follows the cursor across it, so the panel reads as a lit
   surface with depth rather than as a block of colour.

   Driven by --sx/--sy, written by app.js. It sits UNDER the text (z-index on
   .band > * lifts the content) and is pointer-events:none, so it can never
   intercept a click. Defaults to the centre, which means the band still looks
   deliberately lit before the cursor ever arrives, and on touch — where there
   is no cursor at all — it simply stays that way. */
.band__glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.8s var(--ease);
  background: radial-gradient(
    38rem 26rem at var(--sx, 50%) var(--sy, 50%),
    /* Missed by the 6 August 2026 recolour — this was still the old teal
       signal, hardcoded rather than tokenised, glowing green on a navy band.
       A light pool has to be LIGHTER than the surface it lands on, so it uses
       the band italic's pale blue rather than the navy accent. */
    rgba(126, 166, 228, 0.20),
    rgba(126, 166, 228, 0.07) 42%,
    transparent 72%
  );
}

.band:hover .band__glow,
.band.is-lit .band__glow { opacity: 1; }

.band > * { position: relative; z-index: 1; }

.rule { width: 1px; height: clamp(3.5rem, 8vw, 5.5rem); margin: 0 auto; background: linear-gradient(180deg, transparent, var(--accent-dim), transparent); }

/* -------------------------------------------------------- honesty plate -- */

/* Given the weight of a specification plate, not a disclaimer. The category
   hides uncertainty, so stating it plainly IS the differentiator — and it
   re-anchors the decision onto the signals that are actually proven. */
.honesty {
  max-width: 42rem;
  margin-inline: auto;
  padding: clamp(1.9rem, 5vw, 3rem);
  background: var(--card);
  border: 1px solid var(--accent-dim);
  border-radius: var(--radius);
  text-align: left;
  display: grid;
  gap: 1.05rem;
  box-shadow: 0 1px 2px rgba(10,14,22,0.03), 0 26px 56px -40px rgba(10,14,22,0.3);
}

.honesty__label { font-family: var(--font-mono); font-size: 0.64rem; letter-spacing: 0.26em; text-transform: uppercase; color: var(--accent); }
.honesty p { color: var(--ink-soft); font-size: var(--step--1); line-height: 1.68; }
.honesty p.honesty__lead { font-family: var(--font-display); font-size: var(--step-2); line-height: 1.1; color: var(--ink); }
/* The kicker was the only semi-bold dark Inter on the plate — a fourth type
   treatment beside the mono rails, the serif lead and the grey body prose, and
   it read as a different voice rather than the closing line of the same one.

   It now takes the display face in italic, which is already this page's
   established gesture for emphasis — the hero sets its second line in <em> for
   exactly this reason. So the plate's closing statement is emphasised the same
   way the page's opening statement is, rather than inventing a local rule.

   font-weight MUST stay 400. Instrument Serif ships at 400 roman and 400
   italic only (see fonts.css); any heavier value makes the browser synthesise
   a bold and smear the glyphs. Emphasis comes from face, slant and size, never
   from weight.

   No extra network cost: the italic file is already fetched for the hero's
   <em>, which is above the fold, so this reuses a face the visitor has by the
   time they reach the plate.

   Tracking is less negative than the -0.032em on h1/h2 because this sits at
   step-1 rather than display size, and because italics need marginally more
   room than their roman. That tracking is optical, not fixed. */
.honesty p.honesty__kicker {
  font-family: var(--font-display);
  font-weight: 400;
  font-style: italic;
  font-size: var(--step-1);
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.honesty__stamp {
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--ink-soft);
  padding-top: 0.85rem; border-top: 1px solid var(--hairline);
}

/* ---------------------------------------------------------------- cards -- */

/* The four promises — an editorial list, not a feature grid.
   ----------------------------------------------------------------------------
   This was four white cards in an auto-fit grid that collapsed to a 16rem
   minimum, which on a wide screen gave four columns roughly 28 characters wide.
   "We'll show you when we're unsure" needed four lines to say six words, the
   bodies all started at different heights, and because the cards equalised to
   the tallest one, three of them carried a third of their height as dead space.
   Bold sans headings in a box with a hover-lift is the visual grammar of a SaaS
   feature section, and this page had already spent that grammar twice — on the
   channel readouts, where a boxed instrument panel is the right metaphor, and on
   the reserve card.

   These are statements, so they are set as statements: two columns, so the
   measure is wide enough for a heading to land on one or two lines; the display
   serif rather than Inter bold, which is the voice the rest of the page uses for
   anything it means; numbered 01–04 because the heading above promises four
   things and counting them is both a design device and a small act of rigour;
   and a hairline instead of a box, which is what makes it read expensive.

   The icons are gone. With numbers they were redundant, and a warning circle, a
   padlock and a heart are the three most generic marks in the category — they
   were doing more harm than the space they occupied. */
.cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2.75rem, 6vw, 4rem) clamp(2.5rem, 5vw, 4.5rem);
  margin-top: clamp(3.5rem, 8vw, 5.5rem);
  counter-reset: promise;
}

@media (min-width: 44rem) {
  .cards { grid-template-columns: 1fr 1fr; }
}

.card {
  display: grid;
  gap: 0.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline-strong);
}

/* Counter rather than markup: the numbers stay correct if one is ever added,
   removed or reordered. */
.card::before {
  counter-increment: promise;
  content: counter(promise, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  color: var(--accent);
}

.card h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--step-2);
  line-height: 1.08;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

/* A step up from the old --step--1. The narrow columns forced small type; with
   a real measure the body can be read at full size, which is itself part of
   looking unhurried. */
.card p {
  color: var(--ink-soft);
  font-size: var(--step-0);
  line-height: 1.6;
  max-width: 36ch;
}

/* -------------------------------------------------------------- reserve -- */

.reserve {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(22rem, 0.88fr);
  gap: clamp(3rem, 7vw, 6.5rem);
  align-items: center;
  border-radius: clamp(1.5rem, 3vw, 2.25rem);
  background:
    radial-gradient(55rem 32rem at 5% 0%, rgba(110, 168, 232, 0.11), transparent 62%),
    linear-gradient(145deg, #0B1729 0%, #081321 100%);
  border: 1px solid rgba(157, 187, 232, 0.22);
  padding: clamp(2.5rem, 6vw, 5rem);
  overflow: hidden;
  box-shadow:
    0 1px 0 rgba(255,255,255,0.045) inset,
    0 45px 95px -62px rgba(0,0,0,0.72);
}

.reserve::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, rgba(255,255,255,0.035), transparent 30%, transparent 72%, rgba(110,168,232,0.025));
  pointer-events: none;
}

.reserve > * { position: relative; }

.reserve__statement { align-self: start; }

.reserve__eyebrow,
.reserve__offer-label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.reserve__headline {
  max-width: 14ch;
  margin-top: clamp(1.6rem, 3.5vw, 2.5rem);
  font-family: var(--font-display);
  font-size: clamp(2.65rem, 5vw, 4.7rem);
  font-weight: 400;
  line-height: 0.98;
  letter-spacing: -0.038em;
  text-wrap: balance;
}

.reserve__headline em {
  display: block;
  margin-top: 0.2em;
  color: var(--accent);
  font-style: italic;
  font-weight: 400;
}

.reserve__offer {
  min-width: 0;
  padding-left: clamp(2rem, 4.5vw, 4rem);
  border-left: 1px solid var(--hairline);
}

.reserve__offer-label {
  color: var(--accent);
  line-height: 1.6;
}

.reserve__benefits {
  display: grid;
  margin-top: 1.2rem;
  border-bottom: 1px solid var(--hairline);
}

.reserve__benefit {
  display: grid;
  grid-template-columns: 2.25rem 1fr;
  gap: 0.8rem;
  align-items: center;
  padding-block: 1rem;
  border-top: 1px solid var(--hairline);
}

.reserve__benefit > span {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  color: var(--signal);
}

.reserve__benefit strong,
.reserve__benefit small {
  display: block;
}

.reserve__benefit strong {
  font-size: 0.95rem;
  font-weight: 550;
  letter-spacing: -0.01em;
}

.reserve__benefit small {
  margin-top: 0.1rem;
  color: var(--ink-soft);
  font-size: 0.78rem;
}

.reserve__button {
  width: 100%;
  margin-top: 1.6rem;
}

.availability {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.4rem;
  padding-top: 1.05rem;
  border-top: 1px solid var(--hairline);
  color: var(--ink-soft);
  font-size: 0.8rem;
  line-height: 1.4;
}

.availability > span,
.availability b { white-space: nowrap; }
.availability b { font-weight: 500; color: var(--ink-soft); }

.availability__count {
  font-family: var(--font-mono);
  font-size: 1.05rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

/* The checkout page's includes grid already closes with its own hairline,
   so the counter row draws no top rule of its own there — one line, not two. */
.checkout-product .availability { margin-top: 0; padding-block: 1rem; border-top: 0; border-bottom: 1px solid var(--hairline); }

/* Same story under the bottom section's benefits list. */
.availability--prominent {
  margin-top: 0;
  padding-block: 1.1rem;
  border-top: 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 0.9rem;
}
.availability--prominent .availability__count { font-size: 1.4rem; }

.reserve__assurance {
  max-width: 31rem;
  margin: 0.85rem auto 0;
  color: var(--ink-soft);
  font-size: 0.73rem;
  line-height: 1.5;
  text-align: center;
}

.reserve__caveat {
  max-width: 47rem;
  margin: 1.5rem auto 0;
  padding: 0;
  border: 0;
  color: var(--ink-soft);
  font-size: 0.82rem;
  line-height: 1.55;
  text-align: center;
}

@media (max-width: 52rem) {
  .reserve {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  .reserve__headline { max-width: 15ch; }

  .reserve__offer {
    padding: 2rem 0 0;
    border-left: 0;
    border-top: 1px solid var(--hairline);
  }
}

@media (max-width: 34rem) {
  .reserve { padding: 2rem 1.35rem; }
  .reserve__headline { font-size: clamp(2.35rem, 12vw, 3.3rem); }
  .reserve__benefit { grid-template-columns: 1.8rem 1fr; }
}

/* ------------------------------------------------------------------ faq -- */

.faq { max-width: 42rem; margin-inline: auto; margin-top: clamp(2.5rem, 6vw, 3.5rem); }

.faq details { border-bottom: 1px solid var(--hairline); }

.faq summary {
  list-style: none;
  cursor: pointer;
  padding-block: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  font-weight: 500;
  transition: color 0.35s var(--ease-soft);
}

.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--accent); }

.faq summary::after {
  content: '';
  flex: none;
  width: 10px; height: 10px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform 0.4s var(--ease);
  opacity: 0.45;
}

.faq details[open] summary::after { transform: rotate(-135deg) translateY(-2px); }
.faq details p { padding-bottom: 1.6rem; color: var(--ink-soft); font-size: var(--step--1); line-height: 1.68; max-width: 38rem; }

/* --------------------------------------------------- confirmation page -- */

.confirm-mark {
  width: 70px; height: 70px;
  margin-inline: auto;
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--signal);
  border: 1px solid var(--signal);
  background: var(--signal-soft);
}

.timeline { display: grid; gap: 2rem; max-width: 32rem; margin: clamp(3rem,7vw,4rem) auto 0; text-align: left; }
.timeline__item { display: grid; gap: 0.45rem; padding-left: 1.6rem; border-left: 1px solid var(--hairline-strong); }
.timeline__when { font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--accent); }
.timeline__item p { color: var(--ink-soft); font-size: var(--step--1); line-height: 1.62; }
.timeline__item strong { color: var(--ink); font-weight: 600; }

/* ----------------------------------------------------- reservation page -- */

.checkout-page { min-height: 100svh; }

.nav--checkout {
  background: rgba(11, 23, 41, 0.88);
  border-bottom-color: var(--hairline);
  backdrop-filter: blur(18px) saturate(130%);
  -webkit-backdrop-filter: blur(18px) saturate(130%);
}

.checkout-shell {
  min-height: calc(100svh - 8rem);
  padding-block: clamp(8rem, 12vw, 10rem) clamp(4rem, 8vw, 7rem);
  background:
    radial-gradient(55rem 38rem at 12% 12%, rgba(110, 168, 232, 0.10), transparent 62%),
    var(--paper);
}

.checkout-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(3rem, 7vw, 7rem);
  align-items: start;
}

.checkout-product { min-width: 0; max-width: 34rem; }
.checkout-product h1 { margin-top: 1.7rem; max-width: 9ch; }

.checkout-product__lede {
  max-width: 31rem;
  margin-top: 1.4rem;
  color: var(--ink-soft);
  font-size: var(--step-1);
  line-height: 1.55;
}

.checkout-includes {
  display: grid;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  border-block: 1px solid var(--hairline);
}

.checkout-includes > div {
  display: grid;
  grid-template-columns: minmax(8rem, 0.72fr) 1fr;
  gap: 1.25rem;
  align-items: baseline;
  padding-block: 1rem;
}

.checkout-includes > div + div { border-top: 1px solid var(--hairline); }
.checkout-includes strong { font-size: 0.95rem; font-weight: 600; }
.checkout-includes span { color: var(--ink-soft); font-size: 0.85rem; }

.checkout-assurance {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.8rem;
  margin-top: 1.5rem;
  color: var(--ink-soft);
  font-size: 0.82rem;
  line-height: 1.55;
}

.checkout-assurance > span { color: var(--signal); font-weight: 700; }
.checkout-assurance strong { color: var(--ink); font-weight: 600; }

.checkout-card {
  min-width: 0;
  border: 1px solid var(--hairline-strong);
  border-radius: clamp(1.4rem, 3vw, 2rem);
  background:
    radial-gradient(circle at 80% 0%, rgba(110, 168, 232, 0.09), transparent 42%),
    linear-gradient(145deg, rgba(19, 35, 60, 0.98), rgba(8, 18, 33, 0.98));
  box-shadow: 0 2rem 5rem rgba(0, 5, 15, 0.32);
  padding: clamp(1.3rem, 3.5vw, 2rem);
}

.finish-fieldset { border: 0; }

.finish-fieldset legend,
.customer-fields label > span {
  display: block;
  color: var(--ink-soft);
  font-size: 0.78rem;
  font-weight: 500;
}

.finish-options { display: grid; gap: 0.7rem; margin-top: 0.85rem; }

.finish-option {
  position: relative;
  display: grid;
  grid-template-columns: 5.2rem minmax(0, 1fr) auto;
  gap: 1rem;
  align-items: center;
  min-height: 6.2rem;
  padding: 0.55rem 0.85rem 0.55rem 0.55rem;
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: 1rem;
  background: rgba(255,255,255,0.018);
  cursor: pointer;
  transition: border-color 0.25s var(--ease-soft), background 0.25s var(--ease-soft), transform 0.25s var(--ease);
}

.finish-option:hover { transform: translateY(-1px); border-color: var(--hairline-strong); }
.finish-option.is-selected { border-color: var(--signal); background: var(--signal-soft); }

.finish-option__media {
  align-self: stretch;
  overflow: hidden;
  border-radius: 0.7rem;
  background: #F4F4F2;
}

.finish-option__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 69%; }
.finish-option__copy { display: grid; align-content: center; line-height: 1.3; }
.finish-option__copy > strong { margin-bottom: 0.38rem; font-size: 0.98rem; font-weight: 600; }
.finish-option__founding {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.48rem;
  align-items: baseline;
}
.finish-option__founding b { color: var(--ink); font-size: 1rem; font-weight: 650; }
.finish-option__founding em {
  color: var(--signal);
  font-size: 0.58rem;
  font-style: normal;
  font-weight: 650;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.finish-option__retail {
  display: flex;
  gap: 0.35rem;
  align-items: baseline;
  margin-top: 0.08rem;
  color: var(--ink-soft);
  font-size: 0.71rem;
}
.finish-option__retail b { color: var(--ink); font-size: 0.76rem; font-weight: 550; }

.finish-option__qty { justify-self: end; }
.finish-option:not(.is-selected) .finish-option__qty output { opacity: 0.45; }

.customer-fields { display: grid; gap: 1rem; margin-top: 1.5rem; }
.customer-fields label { display: grid; gap: 0.45rem; }

.customer-fields input {
  width: 100%;
  min-height: 3.35rem;
  border: 1px solid var(--hairline-strong);
  border-radius: 0.85rem;
  background: rgba(8, 18, 33, 0.7);
  color: var(--ink);
  font: inherit;
  font-size: 0.94rem;
  padding-inline: 1rem;
  transition: border-color 0.25s var(--ease-soft), box-shadow 0.25s var(--ease-soft);
}

.customer-fields input:focus {
  outline: none;
  border-color: var(--signal);
  box-shadow: 0 0 0 3px var(--signal-soft);
}

.form-honeypot { position: absolute !important; left: -9999px !important; }

.qty-stepper {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.qty-stepper button {
  width: 2.1rem;
  height: 2.1rem;
  border: 1px solid var(--hairline);
  border-radius: 50%;
  background: transparent;
  color: inherit;
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.15s ease, opacity 0.15s ease;
}

.qty-stepper button:hover:not(:disabled) { border-color: currentColor; }
.qty-stepper button:disabled { opacity: 0.3; cursor: default; }

.qty-stepper output {
  min-width: 2.2rem;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
}

.checkout-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.5rem;
  padding-block: 1rem;
  border-block: 1px solid var(--hairline);
}

.checkout-total span,
.checkout-total small { display: block; }
.checkout-total span { font-size: 0.88rem; font-weight: 600; }
.checkout-total small { margin-top: 0.15rem; color: var(--ink-faint); font-size: 0.68rem; }
.checkout-total strong { font-family: var(--font-display); font-size: 2.15rem; font-weight: 400; line-height: 1; }

.checkout-submit { width: 100%; margin-top: 1.25rem; }
.checkout-submit:disabled { cursor: wait; opacity: 0.72; transform: none; }
.checkout-submit__loading[hidden], .checkout-submit__label[hidden] { display: none; }

.form-error {
  margin-top: 1rem;
  padding: 0.8rem 0.9rem;
  border: 1px solid rgba(240, 113, 132, 0.45);
  border-radius: 0.75rem;
  background: rgba(240, 113, 132, 0.08);
  color: #F3B1BD;
  font-size: 0.78rem;
  line-height: 1.45;
}

.checkout-fineprint {
  max-width: 32rem;
  margin: 0.75rem auto 0;
  color: var(--ink-faint);
  font-size: 0.67rem;
  line-height: 1.5;
  text-align: center;
}

.checkout-footer { padding-bottom: 3rem; }

@media (min-width: 62rem) {
  .checkout-layout { grid-template-columns: minmax(0, 0.88fr) minmax(28rem, 0.78fr); justify-content: space-between; }
  .checkout-card { position: sticky; top: 6.5rem; }
}

@media (max-width: 38rem) {
  .finish-option { grid-template-columns: 4.5rem minmax(0, 1fr) auto; min-height: 5.6rem; gap: 0.75rem; }
  .finish-option__qty button { width: 1.8rem; height: 1.8rem; font-size: 0.95rem; }
  .finish-option__qty output { min-width: 1.5rem; font-size: 0.95rem; }
  .checkout-includes > div { grid-template-columns: 1fr; gap: 0.15rem; }
}

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

.footer { border-top: 1px solid var(--hairline); padding-block: 3.5rem 7rem; color: var(--ink-soft); font-size: var(--step--1); }
.footer__inner { display: flex; flex-direction: column; gap: 1.5rem; align-items: flex-start; justify-content: space-between; }

@media (min-width: 48rem) { .footer__inner { flex-direction: row; align-items: center; } }

.footer__legal { max-width: 44rem; line-height: 1.6; }

@media (max-width: 34rem) {
  .nav__contact { display: none; }
}

/* --------------------------------------------------- sticky mobile CTA -- */

.sticky-cta {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 90;
  padding: 0.8rem var(--gutter) calc(0.8rem + env(safe-area-inset-bottom));
  background: rgba(11, 23, 41, 0.94);
  backdrop-filter: blur(18px) saturate(130%);
  -webkit-backdrop-filter: blur(18px) saturate(130%);
  border-top: 1px solid var(--hairline);
  transform: translateY(110%);
  transition: transform 0.55s var(--ease);
  display: flex; gap: 1rem; align-items: center; justify-content: space-between;
}

.sticky-cta.is-visible { transform: translateY(0); }
.sticky-cta__label { font-size: 0.8rem; color: var(--ink-soft); line-height: 1.3; }
.sticky-cta__label strong { color: var(--ink); display: block; font-size: 0.95rem; font-weight: 600; }
.sticky-cta .btn { flex: none; }

@media (min-width: 62rem) { .sticky-cta { display: none; } }

/* ------------------------------------------------------ scroll reveals -- */

/* The base reveal — for prose. Every element on the page used to share this
   single translateY(22px) fade, which is exactly why the motion read as
   generic: a photograph, a spec table and a paragraph are not the same kind of
   thing arriving, and animating them identically tells the eye nothing. The
   rules below give the two that aren't prose their own behaviour. */
/* GATED ON .js, and this is not a detail. This rule hides content, and content
   hidden by JavaScript must never stay hidden when JavaScript doesn't arrive.
   Ungated — as it was until 4 August 2026 — a blocked script, a dropped
   cellular connection or one thrown error left every photograph, card and
   channel tile on this page invisible for ever. That is precisely the defect
   the headings already carry a <head> failsafe for; reveals simply never got
   the same treatment. There is now a matching failsafe in index.html.

   Faster than it was, too: 0.7s rather than 1s. Slow reveals feel expensive
   for exactly one scroll and sluggish on every one after. */
.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  will-change: opacity, transform;
}

.js .reveal.is-in { opacity: 1; transform: none; }

/* Photographs settle out of a slight overscale rather than sliding.

   This was a clip-path wipe for about an hour and it was the wrong call twice
   over: it could only fail CLOSED (a clipped image is invisible, so any missed
   .is-in permanently hides the product), and at 1.15s plus up to 700ms of
   stagger you could scroll past the grid before an image ever appeared. The
   photographs are the most important asset on this page; their reveal should
   be the least clever thing on it. */
.js .shot.reveal {
  transform: scale(1.012);
  transition: opacity 0.8s var(--ease), transform 1.1s var(--ease);
}

.js .shot.reveal.is-in { transform: none; }

/* Cards and channel tiles settle rather than slide, so a row reads as objects
   coming to rest instead of text sliding up. */
.js .card.reveal,
.js .channel.reveal {
  transform: translateY(20px) scale(0.99);
  transition: opacity 0.65s var(--ease), transform 0.75s var(--ease);
}

.js .card.reveal.is-in,
.js .channel.reveal.is-in { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal,
  .js .shot.reveal,
  .js .card.reveal,
  .js .channel.reveal { opacity: 1; transform: none; transition: none; }
  /* Headings must be readable even if the observer never fires — never let a
     motion preference leave the page's actual words invisible. */
  [data-lines] .wi { transform: none !important; opacity: 1 !important; }
  .w { overflow: visible; }
}

/* ==================================================== legal pages ===== */

.legal { padding: clamp(6.5rem, 12vw, 9rem) 0 clamp(3rem, 7vw, 5rem); }
.legal__wrap { max-width: 42rem; }
.legal h1 { font-family: var(--font-display); font-size: clamp(2.4rem, 6vw, 3.4rem); font-weight: 400; letter-spacing: -0.02em; margin-top: 0.6rem; }
.legal__updated { margin-top: 0.9rem; color: var(--ink-faint); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; }
.legal h2 { margin-top: 2.6rem; font-size: 1.05rem; font-weight: 650; letter-spacing: -0.01em; }
.legal p { margin-top: 1rem; color: var(--ink-soft); font-size: 0.92rem; line-height: 1.75; }
.legal ul { margin: 1rem 0 0 1.15rem; display: grid; gap: 0.55rem; color: var(--ink-soft); font-size: 0.92rem; line-height: 1.7; }
.legal a { color: var(--accent); text-decoration: none; }
.legal a:hover { text-decoration: underline; }
.legal strong { color: var(--ink); }

.checkout-agree { margin-top: 0.9rem; color: var(--ink-faint); font-size: 0.72rem; line-height: 1.55; text-align: center; }
.checkout-agree a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 2px; }

/* ===================================================== logo lockup ===== */

.wordmark-logo { display: block; height: 0.82rem; width: auto; }

/* Mobile: the availability row must never clip — smaller count, tighter
   label, and permission to wrap as a last resort. */
@media (max-width: 38rem) {
  .availability { flex-wrap: wrap; font-size: 0.75rem; gap: 0.35rem 0.75rem; }
  .availability--prominent { font-size: 0.78rem; }
  .availability--prominent .availability__count { font-size: 1.2rem; }
}
