/* ============================================================
   NGARO — Design System
   "The light in the dark."
   Ink + Bone base, single warm amber accent.
   The page travels light → dark: dawn hero, dusk footer.
   ============================================================ */

/* ---------- 1. TOKENS ---------- */
:root {
  /* Base */
  --ink:        #0A0A0A;
  --ink-2:      #121212;
  --ink-3:      #1C1C1C;
  --ink-4:      #262626;
  --paper:      #FFFFFF;
  --bone:       #F6F4F0;
  --bone-2:     #EBE7E0;
  /* A clear step below the page ground, warm rather than grey. Used by the
     one section that has to hold white product screens — anything shallower
     and a white panel on bone reads as the same surface. */
  --bone-3:     #E6E0D5;

  /* The accent */
  --amber:      #FF9E2C;
  --amber-soft: #FFB65C;
  --ember:      #E0611A;

  /* Deep tone, from the footer moss — a tone, not an accent */
  --ngahere:    #16241C;

  /* Text */
  --tx:         #0A0A0A;
  --tx-mute:    rgba(10,10,10,.56);
  --tx-faint:   rgba(10,10,10,.34);
  --tx-inv:     #FFFFFF;
  --tx-inv-mute:rgba(255,255,255,.60);
  --tx-inv-faint:rgba(255,255,255,.34);

  /* Lines */
  --line:       rgba(10,10,10,.11);
  --line-2:     rgba(10,10,10,.06);
  --line-inv:   rgba(255,255,255,.14);
  --line-inv-2: rgba(255,255,255,.07);

  /* Type */
  --sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Rhythm — Spartan sits at a flat 40px gutter, near full-bleed, rather
     than a narrow capped container. The cap only bites on large monitors. */
  --gut:    clamp(18px, 3vw, 40px);
  --maxw:   1680px;
  --sec-y:  clamp(88px, 11vw, 180px);
  --r:      14px;
  --r-lg:   22px;
  --r-pill: 999px;

  /* Hero inset box */
  --hero-inset: clamp(8px, 0.85vw, 12px);
  --hero-r:     clamp(14px, 1.4vw, 20px);

  /* Reserved space the fixed footer is revealed into.
     Taller than it needs to be for the text alone: the backdrop is bottom
     anchored, so every pixel of height uncrops the photo from the top and
     drops the NGARO wordmark further clear of the link columns. At the old
     720px ceiling the text finished 8px above the letters. */
  --footer-h: clamp(560px, 86vh, 820px);

  /* Motion */
  --ease:     cubic-bezier(.22,1,.36,1);
  --ease-io:  cubic-bezier(.65,0,.35,1);
  --dur:      .62s;
}

/* ---------- 2. RESET ---------- */
*,*::before,*::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  color: var(--tx);
  background: var(--bone);
  overflow-x: hidden;
  font-feature-settings: "ss01" 1, "cv05" 1;
}

body.is-loading { overflow: hidden; height: 100vh; }

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; background: none; border: none; }
button { cursor: pointer; }
ul, ol { list-style: none; }

::selection { background: var(--amber); color: var(--ink); }

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

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

.skip-link {
  position: absolute; top: -100px; left: var(--gut);
  z-index: 999; padding: 12px 20px;
  background: var(--ink); color: var(--tx-inv);
  border-radius: var(--r-pill); font-size: .82rem;
}
.skip-link:focus { top: 16px; }

/* ---------- 3. LAYOUT PRIMITIVES ---------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gut);
}

.section { padding-block: var(--sec-y); position: relative; }
.section--tight { padding-block: clamp(64px, 7vw, 110px); }

/* Dark surfaces */
.dark {
  background: var(--ink);
  color: var(--tx-inv);
  --tx: var(--tx-inv);
  --tx-mute: var(--tx-inv-mute);
  --tx-faint: var(--tx-inv-faint);
  --line: var(--line-inv);
  --line-2: var(--line-inv-2);
}

/* ---------- 4. TYPE SCALE ---------- */
.h-display {
  font-size: clamp(2.9rem, 8.2vw, 7.2rem);
  line-height: .94;
  letter-spacing: -.045em;
  font-weight: 500;
}

.h1 {
  font-size: clamp(2.3rem, 5.4vw, 4.6rem);
  line-height: 1.02;
  letter-spacing: -.038em;
  font-weight: 500;
}

.h2 {
  font-size: clamp(1.6rem, 2.9vw, 2.5rem);
  line-height: 1.12;
  letter-spacing: -.028em;
  font-weight: 500;
}

.h3 {
  font-size: clamp(1.14rem, 1.6vw, 1.36rem);
  line-height: 1.24;
  letter-spacing: -.018em;
  font-weight: 500;
}

.lede {
  font-size: clamp(1.02rem, 1.35vw, 1.2rem);
  line-height: 1.6;
  color: var(--tx-mute);
  max-width: 56ch;
  font-weight: 400;
}

.body-sm {
  font-size: .935rem;
  line-height: 1.62;
  color: var(--tx-mute);
}

/* The Fabrica signature: a trailing period, in amber */
.dot { color: var(--amber); }

code {
  font-family: var(--mono);
  font-size: .88em;
  padding: 1px 5px;
  border-radius: 5px;
  background: rgba(10,10,10,.09);
}

/* ---------- 5. SECTION HEAD ---------- */
.sec-head {
  display: grid;
  grid-template-columns: 1fr;
  gap: 22px;
  margin-bottom: clamp(44px, 5.5vw, 80px);
}
@media (min-width: 900px) {
  .sec-head--split {
    grid-template-columns: 1.05fr .95fr;
    align-items: end;
    gap: 56px;
  }
}
.sec-head__title { display: grid; gap: 18px; }

/* ---------- 6. BUTTONS (Spartan-style label swap) ---------- */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--paper);
  --btn-bd: var(--ink);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 15px 28px;
  border-radius: var(--r-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  font-size: .92rem;
  font-weight: 500;
  letter-spacing: -.01em;
  overflow: hidden;
  isolation: isolate;
  transition: color .42s var(--ease), border-color .42s var(--ease), transform .42s var(--ease);
  will-change: transform;
}

/* Sweep fill */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--amber);
  transform: translateY(101%);
  transition: transform .52s var(--ease);
}
.btn:hover::before { transform: translateY(0); }
.btn:hover { color: var(--ink); border-color: var(--amber); }
.btn:active { transform: scale(.975); }

/* Label swap */
.btn__label {
  position: relative;
  display: block;
  overflow: hidden;
  height: 1.32em;
}
.btn__label span {
  display: block;
  transition: transform .52s var(--ease);
}
.btn__label span:last-child {
  position: absolute;
  inset: 0;
  transform: translateY(105%);
}
.btn:hover .btn__label span { transform: translateY(-105%); }
.btn:hover .btn__label span:last-child { transform: translateY(0); }

.btn__ico {
  width: 15px; height: 15px;
  flex: none;
  transition: transform .5s var(--ease);
}
.btn:hover .btn__ico { transform: translateX(4px); }

/* Variants */
/* Idles ink, wipes to amber — the reverse of the shared .btn wipe below it,
   which is why the ::before fill has to be restated. Name kept: it is still
   the amber CTA, amber is just where it lands rather than where it starts. */
.btn--amber { --btn-bg: var(--ink); --btn-fg: var(--paper); --btn-bd: var(--ink); }
.btn--amber::before { background: var(--amber); }
.btn--amber:hover { color: var(--ink); border-color: var(--amber); }

.btn--ghost { --btn-bg: transparent; --btn-fg: var(--tx); --btn-bd: rgba(10,10,10,.19); }
.btn--ghost:hover { color: var(--ink); }

.btn--sm { padding: 11px 20px; font-size: .855rem; }

/* Text link with underline wipe */
.tlink {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: .92rem;
  font-weight: 500;
  padding-block: 3px;
}
.tlink::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .48s var(--ease);
}
.tlink:hover::after { transform: scaleX(1); transform-origin: left; }
.tlink:hover { color: var(--ember); }

/* ============================================================
   7. LOADER  — adapted from Fabrica
   ============================================================ */
/* No-JS safety: the loader only exists if JS is alive to dismiss it.
   Otherwise a blocked script would leave a black screen over the site. */
.loader { display: none; }
.js .loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: var(--ink);
  display: grid;
  place-items: center;
  transition: transform 1.05s var(--ease-io);
}
.loader.is-done { transform: translateY(-100%); }

.loader__inner {
  display: grid;
  justify-items: center;
  gap: 30px;
  width: min(560px, 82vw);
  transition: opacity .4s ease, transform .6s var(--ease);
}
.loader.is-done .loader__inner { opacity: 0; transform: translateY(-24px); }

.loader__mark {
  width: 52px; height: 52px;
  color: var(--paper);
  animation: blink 3.4s var(--ease) infinite;
}
@keyframes blink {
  0%, 88%, 100% { transform: scaleY(1); }
  92%           { transform: scaleY(.06); }
  96%           { transform: scaleY(1); }
}

.loader__word {
  font-size: clamp(2.1rem, 6vw, 3.4rem);
  font-weight: 500;
  letter-spacing: .1em;
  color: var(--paper);
  display: flex;
  overflow: hidden;
}
.loader__word span {
  display: block;
  transform: translateY(105%);
  animation: riseIn .82s var(--ease) forwards;
}
@keyframes riseIn { to { transform: translateY(0); } }

.loader__bar {
  width: 100%;
  height: 1px;
  background: rgba(255,255,255,.16);
  position: relative;
  overflow: hidden;
}
.loader__bar i {
  position: absolute;
  inset: 0;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
}

.loader__meta {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(255,255,255,.42);
}
.loader__pct { color: var(--amber); font-variant-numeric: tabular-nums; }

/* Page-transition curtain */
.curtain {
  position: fixed;
  inset: 0;
  z-index: 990;
  background: var(--ink);
  transform: translateY(100%);
  pointer-events: none;
}
.curtain.is-in  { animation: curtainIn  .62s var(--ease-io) forwards; }
.curtain.is-out { animation: curtainOut .62s var(--ease-io) forwards; }
@keyframes curtainIn  { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes curtainOut { from { transform: translateY(0); }    to { transform: translateY(-100%); } }

/* ============================================================
   8. NAV
   ============================================================ */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 200;
  padding-block: 16px;
  transition: transform .55s var(--ease), background .45s ease, border-color .45s ease, padding .45s ease;
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  background: rgba(246,244,240,.78);
  backdrop-filter: blur(18px) saturate(1.6);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  border-bottom-color: var(--line-2);
  padding-block: 11px;
}
.nav.is-hidden { transform: translateY(-105%); }

.nav__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  color: var(--ink);
  flex: none;
}
.brand__mark { width: 30px; height: 30px; transition: transform .55s var(--ease); }
.brand:hover .brand__mark { transform: rotate(-8deg) scale(1.06); }
.brand__word {
  font-size: 1.09rem;
  font-weight: 600;
  letter-spacing: .07em;
}

.nav__links {
  display: none;
  align-items: center;
  gap: 4px;
}
@media (min-width: 940px) { .nav__links { display: flex; } }

.nav__link {
  position: relative;
  padding: 9px 15px;
  font-size: .9rem;
  font-weight: 450;
  color: var(--tx-mute);
  border-radius: var(--r-pill);
  transition: color .35s var(--ease);
}
.nav__link::before {
  content: "";
  position: absolute;
  left: 15px; bottom: 5px;
  width: calc(100% - 30px); height: 1px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .45s var(--ease);
}
.nav__link:hover { color: var(--ink); }
.nav__link:hover::before { transform: scaleX(1); transform-origin: left; }

.nav__cta { display: flex; align-items: center; gap: 10px; flex: none; }
.nav__signin { display: none; }
@media (min-width: 640px) { .nav__signin { display: inline-flex; } }

/* Burger */
/* Flex with an explicit gap, not grid: grid rows stretch to fill the button,
   which puts the bars ~15px apart and stops the X from ever closing. */
.burger {
  width: 42px; height: 42px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4.5px;
  border-radius: 50%;
  border: 1px solid var(--line);
  flex: none;
}
@media (min-width: 940px) { .burger { display: none; } }
.burger i {
  display: block;
  width: 17px; height: 1.5px;
  background: var(--ink);
  transition: transform .4s var(--ease), opacity .3s ease;
}
.burger.is-open i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.burger.is-open i:nth-child(2) { opacity: 0; }
.burger.is-open i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Nav sits above the dark menu overlay — invert it so it stays visible */
.nav.is-inverted {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom-color: transparent;
}
.nav.is-inverted .brand { color: var(--paper); }
.nav.is-inverted .burger { border-color: rgba(255,255,255,.3); }
.nav.is-inverted .burger i { background: var(--paper); }

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: var(--ink);
  color: var(--tx-inv);
  display: grid;
  align-content: center;
  gap: 6px;
  padding: 0 var(--gut);
  clip-path: inset(0 0 100% 0);
  transition: clip-path .72s var(--ease-io);
  pointer-events: none;
}
.mobile-menu.is-open { clip-path: inset(0 0 0 0); pointer-events: auto; }
.mobile-menu a {
  font-size: clamp(2rem, 9vw, 3.2rem);
  font-weight: 500;
  letter-spacing: -.03em;
  padding-block: 8px;
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .5s var(--ease), transform .5s var(--ease), color .3s ease;
}
.mobile-menu.is-open a { opacity: 1; transform: none; }
.mobile-menu a:hover { color: var(--amber); }

/* ============================================================
   9. HERO  — adapted from Spartan AI
   ============================================================ */
/* An inset rounded box, not a full-bleed band. The owl photo fills it as a
   backdrop; the type sits on top.

   The layout follows Spartan's hero in three phases:
     · ≥1200px      row — type left, reserved space right, box locked to viewport height
     · 810–1199px   column — the reserved space drops under the type, still capped at 240px
     · <810px       column — the cap tightens to keep the box clear of the midline
   Below 1200px the box stops being viewport-height and grows with its content. */
.hero {
  position: relative;
  margin: var(--hero-inset);
  height: min(880px, calc(100svh - var(--hero-inset) * 2));
  min-height: 540px;
  display: flex;
  flex-direction: column;
  border-radius: var(--hero-r);
  overflow: hidden;
  isolation: isolate;
  background: var(--bone-2);
}

/* The owl — a full-bleed backdrop behind everything in the box */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
/* Which way the owl drifts as the window narrows is set by the X in
   object-position, and the pivot is the bird's own place in the frame (~48%):
     X above 48% → crops harder off the LEFT as the box narrows → bird slides left
     X below 48% → crops off the RIGHT instead            → bird slides right
   The old 78% was above the pivot, which dragged the bird left behind the type.
   Staying well below it keeps the bird moving right into the clear. */
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 10% 72%;
  will-change: transform;
}
@media (max-width: 1199.98px) {
  .hero__media img { object-position: 25% 70%; }
}
/* Phone: the box is now so tall against its width that the photo is scaled to
   ~4× the box width. Only a near-centre crop keeps the whole bird in frame —
   pushing it further right clips it off the edge entirely. */
@media (max-width: 809.98px) {
  .hero__media img { object-position: center 70%; }
}

/* ---------- Phase 1 · large (≥1200px) ---------- */
.hero__body {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: clamp(26px, 3.4vw, 52px);
  /* Top padding lands on 150px at any normal desktop height, matching phase 2
     so the title sits at the same height in both. It stays viewport-height
     aware so short windows still fit the fixed-height box without clipping.
     Bottom padding must clear the marquee bar pinned inside the box (~92px). */
  padding-top: clamp(94px, 17vh, 150px);
  padding-bottom: clamp(112px, 13vh, 138px);
}

.hero__top {
  flex: 1 1 560px;
  min-width: 0;
  max-width: 560px;
  display: grid;
  gap: clamp(14px, 1.7vw, 23px);
  /* Type rides at the top of the box rather than centring with the card, so it
     holds the same height it has once the layout stacks in phase 2 */
  align-self: flex-start;
}

/* Pure sizing contract — nothing is drawn here. It stands in for the floating
   object that used to occupy this corner of the hero, because the hero's
   height below 1200px is the sum of its flow and the photograph is positioned
   against that height. Let the column collapse and the photo box shortens with
   it, which re-crops the owl; hold the box and the composition is unchanged.

   aspect-ratio reproduces the square the solid stood in; the margin reproduces
   the caption strip that sat under it. */
.hero__reserve {
  flex: 0 1 240px;
  min-width: 0;
  max-width: 240px;
  aspect-ratio: 1;
  margin-bottom: 24px;
}

/* One CTA now, and on a phone it takes the full column rather than sitting as
   a short pill against a wide screen edge */
@media (max-width: 559px) {
  .hero__actions { display: grid; gap: 10px; }
  .hero__actions .btn { width: 100%; }
}

.hero__title {
  font-size: clamp(2.5rem, 5.8vw, 4.9rem);
  line-height: .96;
  letter-spacing: -.045em;
  font-weight: 500;
  max-width: 12ch;
}
.hero__title em {
  font-style: normal;
  color: var(--ember);
}

.hero__sub {
  max-width: 46ch;
  font-size: clamp(1rem, 1.3vw, 1.16rem);
  line-height: 1.58;
  color: rgba(10,10,10,.66);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

.hero__note {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(10,10,10,.44);
}

/* Scroll cue */
.hero__cue {
  position: absolute;
  right: 0; bottom: 118px;
  display: none;
  align-items: center;
  gap: 12px;
  writing-mode: vertical-rl;
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(10,10,10,.4);
}
/* The cue only belongs to the phase where the hero is locked to viewport height */
@media (min-width: 1200px) { .hero__cue { display: flex; } }
.hero__cue i {
  width: 1px; height: 58px;
  background: linear-gradient(to bottom, rgba(10,10,10,.3), transparent);
  animation: cueDrop 2.2s var(--ease) infinite;
}
@keyframes cueDrop {
  0%   { transform: scaleY(0); transform-origin: top; }
  50%  { transform: scaleY(1); transform-origin: top; }
  51%  { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

/* ---------- Phase 2 · medium (810–1199px) ----------
   The row becomes a column: the card drops under the title text but keeps its
   320px cap, and the box stops being viewport-height. The marquee un-pins and
   joins the flow at the bottom of the box. */
@media (max-width: 1199.98px) {
  .hero {
    height: auto;
    min-height: 0;
  }
  .hero__body {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: clamp(48px, 6.4vw, 70px);
    padding-top: clamp(118px, 15vw, 150px);
    padding-bottom: 40px;
  }
  .hero__top {
    flex: none;
    width: 100%;
    max-width: 620px;
  }
  .hero__reserve {
    flex: none;
    width: 100%;
  }
}

/* ---------- Phase 3 · mobile (<810px) ----------
   Phase 2's arrangement, tightened, with the 320px cap off so the card runs the
   full width of the type column.

   The photo stays a backdrop but no longer starts at the top of the box. Above
   it sits a band in the photo's own sky tone (#f0f1f0, sampled off the frame),
   so the join reads as continuous sky rather than a box laid on top — it just
   drops the bird clear of the title.

   That band has to deepen as the screen narrows. `cover` scales the photo by
   the box's height, so a narrow box means a huge over-scale: at 809px the owl
   renders about a quarter of the width and sits happily beside the type, but at
   375px it would be over half the width. Starting the photo lower shortens the
   box, which shrinks the owl and drops it below the words instead of behind
   them. Hence the vw-driven offset rather than a fixed one. */
@media (max-width: 809.98px) {
  .hero {
    background: #f0f1f0;
  }
  /* Widening the frame past the box and anchoring it left is what carries the
     bird right — it runs the photo's right side off the screen edge. Cropping
     with object-position alone tops out around 58% across, because shortening
     the box also cuts the horizontal overflow there is to push against. */
  .hero__media {
    /* 250px at 809 (just under the title, bird beside the type) sliding to
       430px by ~680 (under the whole text block). The handover has to happen
       this fast because the type column's share of the width grows as the
       screen narrows: by ~680px the note's tail reaches the bird, and below
       that there is no arrangement with words to the left of it.
       430px lands in the 28px window between the note's baseline and the top
       of the card, so the words stay off the photo and the card stays wholly
       on it. */
    top: clamp(250px, calc(1430px - 145vw), 430px);
    right: auto;
    width: 140%;
  }
  .hero__media img {
    object-position: 0% 50%;
  }

  .hero__body {
    gap: 28px;
    padding-top: clamp(88px, 22vw, 112px);
    padding-bottom: 28px;
  }
  /* Type and card share one full-width column here — the title and paragraph
     keep their own ch-based caps, so nothing runs long */
  .hero__top {
    max-width: none;
  }
  /* Drop the authored break and narrow the measure, so the sub reflows over
     three lines instead of the two it holds at the larger phases */
  .hero__sub-br {
    display: none;
  }
  .hero__sub {
    max-width: 24ch;
  }
  .hero__reserve {
    /* Never reaches the midline: the box starts one gutter inside the hero
       edge, so half the viewport less that inset puts its right edge exactly on
       the midline, and the 10px keeps it short of it. Width is the binding
       dimension on a phone — height follows from the aspect-ratio — so this cap
       is what sets how much room the owl is left. */
    max-width: min(240px, calc(50vw - var(--gut) - var(--hero-inset) - 10px));
  }
}

/* The CTA goes full-width here, which drops the note below where the phase-3
   clamp leaves the photo. The photo has to follow it down or the note lands
   back on the bird. Across 320–559 the note now bottoms out at 440, so 446
   clears it at every width in the range with six pixels to spare.

   Retuned from 484 when the hero lost its second CTA: the note rose about
   50px, and the photo is bottom-anchored, so leaving the old value simply
   opened 50px of empty sky above the bird. The second constraint that used to
   bracket this number — starting the photo before the floating card so the
   card sat wholly on it — went with the card itself, which now draws nothing. */
@media (max-width: 559.98px) {
  .hero__media {
    top: 446px;
  }
}

/* Below ~340px the photo's over-scale finally outruns the screen and the bird's
   trailing edge clips off the right. Easing the crop back pulls it into frame;
   it costs a few percent of the rightward push at a width almost nothing uses.
   Retuned from 14% after the floating object grew: a taller object makes a
   taller hero, a taller photo box and so a wider over-scale to rein in. */
@media (max-width: 339.98px) {
  .hero__media img {
    object-position: 14% 50%;
  }
}

/* ---------- Trusted-by marquee — sits ON the hero image ---------- */
.trust {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 3;
  padding-block: 18px;
}
.trust__label {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .17em;
  text-transform: uppercase;
  color: rgba(255,255,255,.8);
  text-shadow: 0 1px 3px rgba(0,0,0,.35);
  margin-bottom: 12px;
}

/* Below 1200px the marquee un-pins and joins the flow under the photo */
@media (max-width: 1199.98px) {
  .trust {
    position: relative;
    padding-top: 0;
    padding-bottom: 40px;
  }
}

.marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: slide var(--speed, 42s) linear infinite;
  /* Deliberately never pauses on hover — the glide stays constant */
}
.marquee--rev .marquee__track { animation-direction: reverse; }
@keyframes slide { to { transform: translateX(-50%); } }

.marquee__group {
  display: flex;
  align-items: center;
  gap: clamp(38px, 5vw, 70px);
  padding-right: clamp(38px, 5vw, 70px);
  flex: none;
}
.trust__item {
  font-size: clamp(.95rem, 1.35vw, 1.14rem);
  font-weight: 500;
  letter-spacing: -.015em;
  color: #fff;
  text-shadow: 0 1px 4px rgba(0,0,0,.4);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 10px;
}

/* ============================================================
   10. PROOF — scroll-bold statement + data cards, from Spartan AI
   ============================================================ */
.proof { background: var(--bone); }

/* Three lines, at every width that can hold them.

   The cap is in em, not ch or px, which is what makes the line count stable:
   the measure scales with the type, so the characters per line — and therefore
   the number of rows — stay put as the heading grows. The floor of the clamp
   is what decides how far down that holds, because below it the type stops
   shrinking while the column keeps narrowing. Dropped from 1.5rem so three
   lines survive to ~600px.

   Under that, three lines would need roughly 13px type for this sentence, so
   the statement is allowed to wrap to four on a phone. Legibility wins; the
   effect still reads, because it is the travelling highlight that carries it,
   not the silhouette of the block. */
.proof__text {
  font-size: clamp(1.22rem, 3.6vw, 2.9rem);
  line-height: 1.26;
  letter-spacing: -.035em;
  font-weight: 450;
  max-width: 24.6em;
}
.proof__text .w {
  color: rgba(10,10,10,.17);
  font-weight: 400;
  transition: color .5s var(--ease), font-weight .5s var(--ease);
  display: inline-block;
  white-space: pre;
}
.proof__text .w.on {
  color: var(--ink);
  font-weight: 550;
}
.proof__text .w.hl.on { color: var(--ember); }

.proof__sub {
  margin-top: clamp(20px, 2.2vw, 30px);
  max-width: 58ch;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--tx-mute);
}

/* Spartan's asymmetric row: tall card · stacked pair · tall card. The pair
   splits the same height as its neighbours, so the cards all bottom out on one
   line. Rows are 1fr/auto rather than Spartan's fixed 210+95 because these
   captions are longer than theirs and would overflow a locked height. */
.proof__grid {
  --proof-gap: clamp(10px, 1vw, 14px);
  margin-top: clamp(40px, 5vw, 68px);
  display: grid;
  gap: var(--proof-gap);
}
.proof__stack {
  display: grid;
  gap: var(--proof-gap);
  grid-template-rows: 1fr auto;
}
@media (min-width: 860px) {
  .proof__grid { grid-template-columns: repeat(3, 1fr); }
}

.proof__card {
  border-radius: var(--r-lg);
  padding: clamp(20px, 1.9vw, 28px);
  display: flex;
  flex-direction: column;
  /* Icon pinned top, text pinned bottom — the gap only opens once the column
     is taller than its content, which is what gives the tall cards their air */
  justify-content: space-between;
  gap: clamp(30px, 4vw, 56px);
}
.proof__card--fill {
  background: var(--ink);
  color: var(--tx-inv);
}
.proof__card--tint { background: rgba(10,10,10,.05); }
/* Dashed, not solid: the card it carries is the one about being open to
   inspection, and it is the only card here without a filled surface */
.proof__card--dash {
  border: 1px dashed rgba(10,10,10,.26);
  justify-content: center;
}
.proof__card--row {
  background: rgba(10,10,10,.05);
  justify-content: center;
}

.proof__ico {
  flex: none;
  width: clamp(44px, 3.4vw, 54px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: var(--r);
  background: var(--paper);
  color: var(--ink);
}
.proof__ico svg { width: 46%; height: 46%; }
/* On bone, a white tile would barely register — invert it, which also plays
   the tint card off the filled one rather than repeating it */
.proof__card--tint .proof__ico {
  background: var(--ink);
  color: var(--tx-inv);
}

.proof__body { min-width: 0; }
.proof__fig {
  font-size: clamp(1.85rem, 2.7vw, 2.6rem);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1.04;
  margin-bottom: 12px;
}
.proof__fig em { font-style: normal; color: var(--amber); }
.proof__cap {
  font-size: .9rem;
  line-height: 1.55;
  color: var(--tx-mute);
}
.proof__card--fill .proof__cap { color: var(--tx-inv-mute); }

/* The three claims the sliding bar used to carry, amber dots and all — a
   running line rather than pills, which is both what the marquee was and what
   fits: three phrases this long cannot share a 439px row as padded chips, and
   the second row of pills was deep enough to squeeze the card above it. */
.proof__claims {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 9px 16px;
}
/* The dot rides inside its own phrase rather than sitting between two, so a
   wrap can never strand a separator at the start of a line */
.proof__claim {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .11em;
  text-transform: uppercase;
  white-space: nowrap;
}
.proof__claim::before {
  content: "";
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--amber);
}

/* ============================================================
   11. FEATURES  — adapted from Fluence
   ============================================================ */
.feat-grid {
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
@media (min-width: 720px)  { .feat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1060px) { .feat-grid { grid-template-columns: repeat(3, 1fr); } }

.feat {
  position: relative;
  background: var(--bone);
  padding: clamp(26px, 3vw, 38px);
  display: grid;
  align-content: start;
  gap: 14px;
  min-height: 258px;
  isolation: isolate;
  transition: background .5s var(--ease);
}
.feat::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .55s var(--ease);
}
.feat:hover { background: var(--paper); }
.feat:hover::after { transform: scaleX(1); }

.feat__ico {
  width: 44px; height: 44px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--ink);
  margin-bottom: 6px;
  transition: background .5s var(--ease), color .5s var(--ease), transform .5s var(--ease), border-color .5s var(--ease);
}
.feat__ico svg { width: 20px; height: 20px; }
.feat:hover .feat__ico {
  background: var(--amber);
  border-color: var(--amber);
  transform: translateY(-3px) rotate(-5deg);
}

.feat__n {
  position: absolute;
  top: clamp(26px, 3vw, 38px);
  right: clamp(26px, 3vw, 38px);
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .1em;
  color: var(--tx-faint);
}

/* ============================================================
   12. HOW IT WORKS — sticky step list beside a stack of screens
   ============================================================ */
/* Two columns above 1040px, the same breakpoint the rest of the page uses
   for its widest grids. The left column is a sticky accordion of the four
   step names; the right is one product screen per step. Below 1040px the
   left column is dropped entirely and each step's text is re-issued inline
   above its own screen — the copy exists twice in the markup, and exactly
   one copy is ever in the accessibility tree. */
/* The one deep-ground section on the light half of the page. It carries four
   white product screens, and on plain bone those screens read as the same
   surface as the page. The Integrations section that follows is dropped back
   to bone so the rhythm alternates rather than sitting deep twice running. */
.how { background: var(--bone-3); }

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

@media (min-width: 1040px) {
  .how__grid {
    grid-template-columns: minmax(220px, 3fr) 9fr;
    gap: clamp(40px, 5vw, 96px);
    align-items: start;
  }
}

/* ---- Left column: the sticky list ---- */
.how__rail { display: none; }

@media (min-width: 1040px) {
  .how__rail {
    display: block;
    position: sticky;
    /* Clears the fixed nav, then a little air. */
    top: clamp(96px, 13vh, 132px);
  }
}

.steps { display: grid; }

/* Closed steps are hairline-separated rows. The open one leaves the list and
   becomes a card: it lifts onto paper and breaks out past the column edge on
   both sides, so it reads as the thing in front rather than a highlighted
   row. The break-out is margin + padding in equal measure, which keeps the
   text on the same optical left edge as the rows above and below it. */
.step {
  border-top: 1px solid var(--line);
  border-radius: var(--r);
  transition: background .5s var(--ease), box-shadow .5s var(--ease),
              margin .5s var(--ease), padding .5s var(--ease),
              border-color .3s var(--ease);
}
.step:last-child { border-bottom: 1px solid var(--line); }

.step.is-open {
  border-color: transparent;
  background: var(--paper);
  box-shadow: 0 20px 44px -26px rgba(10,10,10,.34), 0 2px 6px rgba(10,10,10,.05);
  margin-inline: -20px;
  padding-inline: 20px;
  margin-block: 6px;
}
/* The card supplies its own edge, so the neighbour's rule would double it */
.step.is-open + .step { border-top-color: transparent; }

.step__h { font: inherit; font-weight: 400; }

.step__btn {
  display: flex;
  align-items: baseline;
  gap: 14px;
  width: 100%;
  padding: 18px 0;
  text-align: left;
  color: var(--tx-mute);
  transition: color .38s var(--ease);
}
.step.is-open > .step__h > .step__btn,
.step__btn:hover { color: var(--tx); }

.step__n {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  color: var(--tx-faint);
  flex: none;
  transition: color .38s var(--ease);
}
.step.is-open .step__n { color: var(--amber); }

.step__name {
  flex: 1;
  font-size: 1.02rem;
  font-weight: 500;
  letter-spacing: -.018em;
  line-height: 1.3;
}

.step__chev {
  width: 15px; height: 15px;
  flex: none;
  align-self: center;
  opacity: .4;
  transition: transform .42s var(--ease), opacity .38s var(--ease);
}
.step.is-open .step__chev { transform: rotate(180deg); opacity: 1; color: var(--amber); }

/* 0fr → 1fr so the panel animates without JS measuring anything */
.step__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .52s var(--ease);
}
.step.is-open .step__body { grid-template-rows: 1fr; }
/* overflow:hidden clips a collapsed panel visually but leaves it readable by
   a screen reader and reachable by Tab, which makes aria-expanded a lie.
   visibility takes it out of both, delayed so it doesn't kill the close. */
.step__inner {
  overflow: hidden;
  visibility: hidden;
  transition: visibility 0s linear .52s;
}
.step.is-open .step__inner { visibility: visible; transition-delay: 0s; }
.step__inner p {
  font-size: .92rem;
  line-height: 1.62;
  color: var(--tx-mute);
  padding-bottom: 22px;
  max-width: 40ch;
}

/* ---- Right column: the screens ---- */
.how__panels {
  display: grid;
  gap: clamp(56px, 6vw, 110px);
}

/* ---- gliding between steps ---- */
/* Native proximity snapping, not hijacked wheel events: the browser only
   pulls when you have already come to rest near a screen, so a deliberate
   long scroll through the section is never fought. main.js adds .snap-how to
   <html> while the section owns the middle of the window and takes it off
   again at both ends, which is what stops the rest of the page from snapping
   and lets you leave the section freely.

   Two-column widths only. Below 1040px each screen has its heading and
   paragraph stacked above it, and centring the screen would push that copy
   off the top of the phone. */
@media (min-width: 1040px) {
  html.snap-how { scroll-snap-type: y proximity; }
  html.snap-how .how__panels .panel { scroll-snap-align: center; }
}
@media (prefers-reduced-motion: reduce) {
  html.snap-how { scroll-snap-type: none; }
}

/* The inline copy — the accordion's job above 1040px */
.panel__lede { display: grid; gap: 8px; margin-bottom: 22px; max-width: 60ch; }
.panel__n {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  color: var(--amber);
}
.panel__h { font-size: 1.14rem; font-weight: 500; letter-spacing: -.018em; line-height: 1.28; }
.panel__lede p { font-size: .93rem; line-height: 1.6; color: var(--tx-mute); }
@media (min-width: 1040px) { .panel__lede { display: none; } }

/* The 4:3 box. Capped so it doesn't become a 900px-tall slab inside the
   1680px container. cqi inside it drives every dimension of the screen,
   so one set of rules covers a 320px phone and a 1000px panel. */
.panel__box {
  container-type: inline-size;
  aspect-ratio: 4 / 3;
  width: 100%;
  max-width: 1000px;
}
/* On a phone the box is only ~340px wide, and 4:3 leaves 254px of height for
   an interface. Since the type scales off the WIDTH, the fix is height, not
   width: go square and the same legible type has room to breathe. */
@media (max-width: 700px) { .panel__box { aspect-ratio: 1 / 1; } }

/* ============================================================
   13b. THE PRODUCT SCREENS
   ============================================================ */
/* Ordinary markup, not canvas — so the screens inherit the page tokens and
   there is one design system here, not two. Everything inside is sized in
   em from the .scr font-size, which is itself a share of the box width. */
.scr {
  height: 100%;
  display: flex;
  overflow: hidden;
  background: var(--paper);
  border: 1px solid rgba(10,10,10,.14);
  border-radius: var(--r-lg);
  /* Sized to the deep ground it sits on — a soft shadow that read as depth on
     bone just looks like blur once the surface behind it darkens. */
  box-shadow: 0 44px 72px -38px rgba(10,10,10,.42),
              0 6px 16px -8px rgba(10,10,10,.10),
              0 1px 2px rgba(10,10,10,.05);
  position: relative;
  font-size: 13px;                        /* fallback where cqi is unsupported */
  font-size: clamp(10.5px, 1.62cqi, 15px);
  line-height: 1.5;
  letter-spacing: -.005em;
}

/* -- the thin app rail -- */
.scr__rail {
  width: 4.7em;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5em;
  padding: 1.5em 0 1.3em;
  border-right: 1px solid var(--line);
  background: var(--bone);
}
.scr__mark { width: 2em; height: 2em; color: var(--ink); }
.scr__mark svg { width: 100%; height: 100%; }
.scr__nav { display: flex; flex-direction: column; gap: 1.1em; flex: 1; }
.scr__nav i {
  width: 1.5em; height: 1.5em;
  border-radius: .45em;
  background: rgba(10,10,10,.07);
  display: block;
}
.scr__nav i.is-on { background: rgba(255,158,44,.34); }
.scr__me {
  width: 2em; height: 2em;
  border-radius: 50%;
  background: var(--ink);
  color: var(--tx-inv);
  font-family: var(--mono);
  font-size: .72em;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* -- header bar -- */
.scr__main { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.scr__bar {
  display: flex;
  align-items: center;
  gap: .9em;
  padding: 1em 1.5em;
  border-bottom: 1px solid var(--line);
  flex: none;
}
.scr__brand {
  font-weight: 600;
  font-size: .92em;
  letter-spacing: .02em;
}
.scr__sep { width: 1px; height: 1.3em; background: var(--line); flex: none; }
.scr__proj { display: grid; gap: .15em; min-width: 0; flex: 1; }
.scr__proj b { font-weight: 500; font-size: .88em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.scr__proj i {
  font-style: normal;
  font-family: var(--mono);
  font-size: .66em;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--tx-faint);
}
.scr__state {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: .5em;
  font-family: var(--mono);
  font-size: .66em;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: .5em 1em;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  color: var(--tx-mute);
  white-space: nowrap;
}
.scr__state--wait { border-color: rgba(255,158,44,.5); color: var(--ember); background: rgba(255,158,44,.09); }
.scr__state--done { border-color: rgba(255,158,44,.5); color: var(--ember); background: rgba(255,158,44,.14); }
.scr__state--live i {
  width: .55em; height: .55em;
  border-radius: 50%;
  background: var(--amber);
  animation: scrPulse 2.2s var(--ease) infinite;
}
@keyframes scrPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,158,44,.55); }
  55%      { box-shadow: 0 0 0 .5em rgba(255,158,44,0); }
}

/* -- body -- */
/* Centred, not top-anchored: none of these screens has enough content to
   fill a 4:3 box, and left at the top each one trails half a panel of dead
   white. The chat screen overrides this by growing .chat to fill instead. */
.scr__body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.1em;
  padding: 1.5em;
  overflow: hidden;
}
.scr__body--chat { background: var(--bone); gap: .9em; }
.scr__body--mid { justify-content: center; align-items: center; text-align: center; }

.scr__title {
  font-size: .95em;
  font-weight: 500;
  letter-spacing: -.015em;
}
.scr__title em { font-style: normal; color: var(--tx-faint); font-weight: 400; }
.scr__note { font-size: .78em; line-height: 1.5; color: var(--tx-faint); }

.scr__acts { display: flex; gap: .7em; flex-wrap: wrap; margin-top: .5em; }
.scr__btn {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  padding: .75em 1.35em;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  font-size: .84em;
  font-weight: 500;
  white-space: nowrap;
}
.scr__btn code { font-size: .92em; background: rgba(10,10,10,.1); padding: 0 .35em; }
.scr__btn--amber { background: var(--amber); border-color: var(--amber); color: var(--ink); }
.scr__btn { transition: transform .18s var(--ease); }
.scr__btn.is-pressed { transform: scale(.955); }

/* ---- screen 01 + 05: the conversation ---- */
/* Bottom-anchored, the way a real thread sits above its composer — otherwise
   a four-message conversation floats in the top third of a 4:3 box. */
.chat {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .85em;
  flex: 1;
  min-height: 0;
}
.chat__row { display: flex; gap: .6em; max-width: 88%; align-items: flex-start; }
.chat__row--me { align-self: flex-end; }
.chat__av {
  width: 1.85em; height: 1.85em;
  flex: none;
  border-radius: 50%;
  background: rgba(255,158,44,.2);
  position: relative;
}
.chat__av::after {
  content: '';
  position: absolute; inset: 0;
  margin: auto;
  width: .62em; height: .62em;
  border-radius: 50%;
  background: var(--ember);
}
.chat__b {
  padding: .8em 1.05em;
  border-radius: 1em;
  font-size: .87em;
  line-height: 1.55;
}
.chat__row--ai .chat__b {
  background: var(--paper);
  border: 1px solid var(--line);
  border-top-left-radius: .3em;
}
.chat__row--me .chat__b {
  background: rgba(255,158,44,.18);
  border: 1px solid rgba(255,158,44,.28);
  border-top-right-radius: .3em;
}
.chat__b--dots { display: inline-flex; gap: .35em; align-items: center; padding: 1em 1.05em; }
.chat__b--dots i {
  width: .38em; height: .38em;
  border-radius: 50%;
  background: var(--tx-faint);
  animation: scrDot 1s ease-in-out infinite;
}
.chat__b--dots i:nth-child(2) { animation-delay: .14s; }
.chat__b--dots i:nth-child(3) { animation-delay: .28s; }
@keyframes scrDot {
  0%, 80%, 100% { transform: translateY(0);      opacity: .38; }
  40%           { transform: translateY(-.3em);  opacity: 1;   }
}

.chat__tags { display: flex; gap: .5em; flex-wrap: wrap; padding-left: 2.45em; }
.chat__tag {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  padding: .45em .9em;
  border-radius: var(--r-pill);
  background: var(--paper);
  border: 1px solid var(--line);
  font-size: .76em;
  white-space: nowrap;
}
.chat__tag-d { width: .5em; height: .5em; border-radius: 50%; background: var(--amber); flex: none; }
.chat__tag-d--off { background: rgba(10,10,10,.2); }

.chat__cite {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: .45em;
  margin-left: 2.45em;
  padding: .45em .9em;
  border-radius: var(--r-pill);
  background: var(--paper);
  border: 1px solid var(--line);
  font-size: .74em;
  color: var(--tx-mute);
  white-space: nowrap;
}
.chat__cite svg { width: .95em; height: .95em; flex: none; }

/* the composer */
.composer {
  display: flex;
  align-items: center;
  gap: .7em;
  flex: none;
  padding: .45em .45em .45em 1.2em;
  border-radius: var(--r-pill);
  background: var(--paper);
  border: 1px solid var(--line);
}
.composer__field {
  flex: 1;
  min-width: 0;
  font-size: .87em;
  color: var(--tx);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.composer__field--idle, .composer__field:empty { color: var(--tx-faint); }
.composer__field:empty::before { content: 'Describe what to build…'; }
/* The placeholder gets out of the way the moment the cursor starts typing */
.composer__field.is-typing:empty::before { content: ''; }
/* Caret only while the fake cursor is actually typing into it */
.composer__field.is-typing::after {
  content: '';
  display: inline-block;
  width: 1px;
  height: 1.05em;
  margin-left: .1em;
  vertical-align: -.16em;
  background: var(--ink);
  animation: scrCaret .9s steps(1) infinite;
}
@keyframes scrCaret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

.composer__send {
  width: 2.2em; height: 2.2em;
  flex: none;
  border-radius: 50%;
  background: var(--ink);
  color: var(--tx-inv);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .18s var(--ease);
}
.composer__send svg { width: 1em; height: 1em; }
.composer__send.is-pressed { transform: scale(.84); }

/* ---- screen 01: the costed plan, said in the conversation ---- */
/* The plan is the assistant's next message, so it is a chat bubble that has
   been let off the 88% leash and given a little more padding. Everything
   inside is a <span> carrying a display from CSS — a bubble is phrasing
   content, and nesting <div>s inside it would be invalid. */
.chat__row--plan { max-width: 100%; }
.chat__b--plan {
  display: grid;
  gap: .9em;
  flex: 1;
  min-width: 0;
  padding: 1.05em 1.15em 1.15em;
  /* Back to the screen's own base, so .bill and .scr__note inside size the
     same as they would on a screen of their own instead of compounding
     against the bubble's .87em. */
  font-size: 1em;
}
.plan__h { font-size: .95em; font-weight: 500; letter-spacing: -.015em; }

.bill { display: grid; gap: .75em; }
.bill__row { display: flex; align-items: baseline; gap: .7em; font-size: .86em; }
.bill__row b { font-weight: 400; }
.bill__row s { flex: 1; border-bottom: 1px dotted var(--line); text-decoration: none; transform: translateY(-.25em); }
.bill__row span { font-family: var(--mono); font-size: .92em; color: var(--tx-mute); white-space: nowrap; }
.bill__row--total { padding-top: .75em; border-top: 1px solid var(--line); }
.bill__row--total b { font-weight: 500; }
.bill__row--total span { color: var(--ember); font-weight: 500; }

/* ---- screen 03: documents in ---- */
.drop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .7em;
  padding: 1.5em;
  border: 1px dashed rgba(10,10,10,.2);
  border-radius: var(--r);
  color: var(--tx-faint);
  font-size: .83em;
  text-align: center;
}
.drop__ico { width: 1.5em; height: 1.5em; flex: none; }

.files { display: grid; gap: .6em; }
.files__row {
  display: flex;
  align-items: center;
  gap: .7em;
  flex-wrap: wrap;
  font-size: .84em;
  padding-bottom: .6em;
  border-bottom: 1px solid var(--line-2);
}
.files__row b { font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.files__row s { flex: 1; text-decoration: none; }
.files__row span { font-family: var(--mono); font-size: .9em; color: var(--tx-faint); white-space: nowrap; }
.files__ok {
  width: 1.15em; height: 1.15em;
  flex: none;
  border-radius: 50%;
  background: rgba(255,158,44,.2);
  position: relative;
}
.files__ok::after {
  content: '';
  position: absolute;
  left: .34em; top: .3em;
  width: .28em; height: .5em;
  border: solid var(--ember);
  border-width: 0 1.4px 1.4px 0;
  transform: rotate(42deg);
}
.files__spin {
  width: 1.15em; height: 1.15em;
  flex: none;
  border-radius: 50%;
  border: 1.4px solid rgba(10,10,10,.12);
  border-top-color: var(--amber);
  animation: scrSpin 1s linear infinite;
}
@keyframes scrSpin { to { transform: rotate(360deg); } }
.files__row--work { color: var(--tx-mute); }
.files__bar {
  flex-basis: 100%;
  height: 2px;
  border-radius: 2px;
  background: rgba(10,10,10,.08);
  overflow: hidden;
}
.files__bar i {
  display: block;
  height: 100%;
  width: 38%;
  border-radius: 2px;
  background: var(--amber);
  animation: scrCrawl 2.6s var(--ease-io) infinite;
}
@keyframes scrCrawl {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(320%); }
}

/* ---- screen 04: the source list ---- */
.srcs { display: grid; gap: .55em; flex: 1; min-height: 0; }
.srcs__row {
  display: flex;
  align-items: center;
  gap: .8em;
  padding: .7em .9em;
  border: 1px solid var(--line);
  border-radius: var(--r);
  font-size: .84em;
  background: var(--paper);
}
.srcs__row b { font-weight: 400; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.srcs__from {
  flex: none;
  font-family: var(--mono);
  font-size: .72em;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .35em .8em;
  border-radius: var(--r-pill);
  background: rgba(255,158,44,.13);
  color: var(--ember);
  white-space: nowrap;
}
.srcs__from--web { background: rgba(10,10,10,.06); color: var(--tx-mute); }
.srcs__x { font-style: normal; color: var(--tx-faint); flex: none; line-height: 1; }

/* ---- screen 05: shape it, then try it ---- */
.scr__cols { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; }
.scr__col { display: flex; flex-direction: column; gap: .9em; padding: 1.4em; min-height: 0; overflow: hidden; }
/* Pinned to the foot of the form column so it doesn't trail off into white */
.scr__note--foot { margin-top: auto; }
.scr__col--form { border-right: 1px solid var(--line); }
.scr__col--try { background: var(--bone); }

.fld { display: grid; gap: .25em; padding-bottom: .7em; border-bottom: 1px solid var(--line-2); }
.fld i {
  font-style: normal;
  font-family: var(--mono);
  font-size: .68em;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--tx-faint);
}
.fld b { font-weight: 400; font-size: .85em; line-height: 1.45; }
.fld--sw b { display: flex; align-items: center; justify-content: space-between; gap: .8em; }
.sw {
  width: 2.4em; height: 1.3em;
  flex: none;
  border-radius: var(--r-pill);
  background: rgba(10,10,10,.12);
  position: relative;
}
.sw s {
  position: absolute;
  top: .2em; left: .2em;
  width: .9em; height: .9em;
  border-radius: 50%;
  background: var(--paper);
  text-decoration: none;
  box-shadow: 0 1px 3px rgba(10,10,10,.24);
}

/* ---- screen 03: the accent swatches ---- */
.fld--sws b { padding-top: .2em; }
.sws { display: flex; gap: .55em; }
.sws__c {
  width: 1.5em; height: 1.5em;
  flex: none;
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 0 1px rgba(10,10,10,.12) inset;
  position: relative;
  transition: box-shadow .34s var(--ease), transform .18s var(--ease);
}
.sws__c.is-pressed { transform: scale(.86); }
/* The ring is drawn outside the dot, so selecting one doesn't shrink it */
.sws__c.is-on { box-shadow: 0 0 0 1px rgba(10,10,10,.12) inset, 0 0 0 2px var(--paper), 0 0 0 3.4px var(--c); }

/* ---- screen 03: the branded portal preview ---- */
/* Everything the end user would see is painted from --brand, which screens.js
   rewrites when the cursor picks a swatch. Amber is the default so the screen
   is correct before any script runs. */
.scr--brand { --brand: 255,158,44; }
.scr--brand .chat__row--me .chat__b {
  background: rgba(var(--brand), .18);
  border-color: rgba(var(--brand), .32);
}
.scr--brand .chat__av { background: rgba(var(--brand), .22); }
.scr--brand .chat__av::after { background: rgb(var(--brand)); }
.scr--brand .chat__row--me .chat__b,
.scr--brand .chat__av,
.scr--brand .chat__av::after,
.scr--brand .port__mark {
  transition: background .5s var(--ease), border-color .5s var(--ease), color .5s var(--ease);
}

.port__head {
  display: flex;
  align-items: center;
  gap: .7em;
  padding-bottom: .85em;
  border-bottom: 1px solid var(--line);
  flex: none;
}
.port__mark {
  width: 2.1em; height: 2.1em;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(var(--brand, 255,158,44), .16);
  color: rgb(var(--brand, 255,158,44));
}
.port__mark svg { width: 1.25em; height: 1.25em; }
.port__id { display: grid; gap: .1em; min-width: 0; }
.port__id b { font-weight: 500; font-size: .88em; }
.port__id i {
  font-style: normal;
  font-family: var(--mono);
  font-size: .68em;
  letter-spacing: .04em;
  color: var(--tx-faint);
}

.chat--mini { gap: .7em; }
.chat--mini .chat__row { max-width: 100%; }

.composer--mini { padding: .4em .4em .4em 1em; }
.composer--mini .composer__send { width: 1.9em; height: 1.9em; }

/* ---- screen 04: finished, and the hosted branch ---- */
.done { display: grid; gap: .7em; justify-items: center; max-width: 30em; }
.done__tick {
  width: 2.8em; height: 2.8em;
  border-radius: 50%;
  background: rgba(255,158,44,.18);
  color: var(--ember);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: .3em;
}
.done__tick svg { width: 1.4em; height: 1.4em; }
.done__h { font-size: 1.1em; font-weight: 500; letter-spacing: -.02em; }
.done__s { font-size: .84em; line-height: 1.55; color: var(--tx-mute); }
.done__gets { display: flex; gap: .7em; flex-wrap: wrap; justify-content: center; margin-top: .5em; }
.done__size { font-family: var(--mono); font-size: .72em; letter-spacing: .06em; color: var(--tx-faint); }
.done__alt { font-size: .82em; line-height: 1.55; color: var(--tx-mute); }

/* ---- screen 04: the download ---- */
/* A tray, the way a browser shows one: name on the left, state on the right,
   a bar under it. Width is locked to the .done column so the bar does not
   change length between the empty and finished states. */
.dl {
  width: 100%;
  margin-top: .5em;
  padding: .85em 1em;
  display: grid;
  gap: .6em;
  text-align: left;
  border-radius: .7em;
  border: 1px solid var(--line);
  background: var(--paper);
}
.dl__row { display: flex; align-items: center; gap: .6em; font-size: .84em; }
.dl__ico { width: 1.15em; height: 1.15em; flex: none; color: var(--tx-faint); }
.dl__ico svg { width: 100%; height: 100%; }
.dl__nm { font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dl__row s { flex: 1; text-decoration: none; }
.dl__pct {
  font-family: var(--mono);
  font-size: .9em;
  color: var(--tx-mute);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.dl__bar { display: block; height: 4px; border-radius: 2px; background: rgba(10,10,10,.1); overflow: hidden; }
/* Driven by --p from the script, one write per step — not a CSS transition,
   so the counter beside it can never drift out of step with the fill */
.dl__bar i {
  display: block;
  height: 100%;
  width: var(--p, 0%);
  border-radius: inherit;
  background: var(--amber);
  transition: width .28s linear;
}
.dl__note { font-size: .74em; }
.dl.is-done .dl__ico { color: var(--ember); }
.dl.is-done .dl__pct { color: var(--ember); font-weight: 500; }

/* ---- narrow screens: trim, don't shrink ---- */
/* On a phone the panel box is a 340px square, and two columns of interface
   simply do not fit inside it. The type is already at its floor, so the fix
   is to remove scaffolding rather than to scale: the drop zone, the footnote
   and a couple of rows go, and what remains still tells the story. Scoped by
   container, so the same markup is untouched at every other size. */
@container (max-width: 470px) {
  .scr--ingest .drop,
  .scr--ingest .scr__note--foot,
  .scr--ingest .files__row:nth-child(3),
  .scr--ingest .files__row:nth-child(4),
  .scr--ingest .srcs__row:nth-child(5),
  .done__size { display: none; }
  .done { gap: .5em; }
}

/* ---- the fake cursor ---- */
/* Absolute inside .scr, not fixed to the viewport, so it travels with the
   panel as the page scrolls. screens.js sets --x/--y in px. */
.scr__cursor {
  position: absolute;
  top: 0; left: 0;
  z-index: 5;
  opacity: 0;
  pointer-events: none;
  transform: translate(var(--x, 0px), var(--y, 0px));
  will-change: transform;
}
.scr__cursor svg { width: 1.35em; height: 1.35em; }
.scr__cursor-beam { display: none; margin: -.68em 0 0 -.34em; }
.scr__cursor.is-beam .scr__cursor-arrow { display: none; }
.scr__cursor.is-beam .scr__cursor-beam { display: block; }

/* ---- animation states ---- */
/* The markup ships each conversation FINISHED. screens.js adds .is-anim only
   once it has taken control, which is what hides the later beats; if that
   script never loads, or motion is reduced, the screens simply read as
   completed conversations. Nothing here hides content by default. */
.scr.is-anim [data-anim="msg"]:not(.is-in),
.scr.is-anim [data-anim="dl"]:not(.is-in),
.scr.is-anim [data-anim="tags"]:not(.is-in) { display: none; }

/* The thinking dots are the one beat that is never part of a finished
   conversation, so they stay hidden until an animation asks for them —
   unscoped, unlike the rules above. */
[data-anim="think"]:not(.is-in) { display: none; }

.scr.is-anim [data-anim].is-in { animation: scrIn .46s var(--ease) both; }
@keyframes scrIn {
  from { opacity: 0; transform: translateY(.5em) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* Idle screens hold still — only the active panel is allowed to move */
.scr:not(.is-live) .files__bar i,
.scr:not(.is-live) .files__spin,
.scr:not(.is-live) .scr__state--live i { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  .scr__state--live i,
  .chat__b--dots i,
  .files__spin,
  .files__bar i,
  .composer__field.is-typing::after { animation: none; }
  .files__bar i { width: 62%; transform: none; }
}

/* ---- how the screens reflow when the box itself gets small ---- */
/* Driven by the panel width, not the viewport, so a screen looks right at
   any size the layout happens to give it. */
@container (max-width: 520px) {
  .scr__rail { display: none; }
  .scr__body, .scr__col { padding: 1.15em; }
  .scr__bar { padding: .85em 1.15em; }
  .scr__proj i, .scr__state { display: none; }
}
@container (max-width: 620px) {
  .scr__cols { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .scr__col--form { border-right: none; border-bottom: 1px solid var(--line); }
  /* Tone and the footnote go; the name, the firm rule and the internet
     switch are the three that carry the point of the screen. */
  .scr__col--form .fld:nth-child(3),
  .scr__col--form .scr__note--foot { display: none; }
}

/* ============================================================
   13. INTEGRATIONS  — adapted from Fluence
   ============================================================ */
/* Back to plain bone — the deep ground belongs to "How it works" above, and
   two deep sections in a row would flatten the pair into one slab. */
.integ { background: var(--bone); }

.integ-grid {
  display: grid;
  gap: 18px;
}
@media (min-width: 860px) { .integ-grid { grid-template-columns: repeat(2, 1fr); } }

.ipanel {
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(24px, 2.8vw, 34px);
  display: grid;
  gap: 20px;
  align-content: start;
}
.ipanel__head { display: grid; gap: 7px; }
.ipanel__chips { display: flex; flex-wrap: wrap; gap: 8px; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 15px 9px 11px;
  border-radius: var(--r-pill);
  background: var(--paper);
  border: 1px solid var(--line);
  font-size: .875rem;
  font-weight: 450;
  letter-spacing: -.01em;
  white-space: nowrap;
  transition: transform .42s var(--ease), border-color .42s var(--ease), box-shadow .42s var(--ease);
}
.chip:hover {
  transform: translateY(-2px);
  border-color: rgba(255,158,44,.6);
  box-shadow: 0 6px 18px rgba(10,10,10,.05);
}
.chip__d {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--amber);
  flex: none;
}
.chip__d--mute { background: rgba(10,10,10,.22); }

/* Local-vs-cloud diagram */
.flow {
  display: grid;
  gap: 12px;
  padding: clamp(20px, 2.4vw, 28px);
  border-radius: var(--r);
  background: var(--ink);
  color: var(--tx-inv);
}
.flow__row {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--mono);
  font-size: .76rem;
  letter-spacing: .04em;
  color: rgba(255,255,255,.72);
}
.flow__row i {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--amber);
  flex: none;
  box-shadow: 0 0 0 4px rgba(255,158,44,.16);
}
.flow__row.is-off i { background: rgba(255,255,255,.2); box-shadow: none; }
.flow__row s { flex: 1; height: 1px; background: rgba(255,255,255,.13); border: 0; }
.flow__row b { font-weight: 400; color: var(--paper); }

/* ============================================================
   14. YOUR API (light → dark pivot)
   ============================================================ */
.pivot {
  background: linear-gradient(to bottom, var(--bone-2) 0%, var(--ink) 62%);
  color: var(--tx-inv);
  --tx: var(--tx-inv);
  --tx-mute: var(--tx-inv-mute);
  --tx-faint: var(--tx-inv-faint);
  --line: var(--line-inv);
}
.pivot .sec-head .h1 { color: var(--ink); }
.pivot .sec-head .lede { color: rgba(10,10,10,.6); }

/* Two cards on one row above 880px — the same breakpoint and the same
   footprint the download-vs-hosted pair used to occupy — with the honest
   footnote spanning both underneath. */
.api { display: grid; gap: 18px; }
@media (min-width: 880px) {
  .api { grid-template-columns: 1fr 1fr; }
  .api__foot { grid-column: 1 / -1; }
}

.api__card {
  border-radius: var(--r-lg);
  padding: clamp(26px, 3vw, 38px);
  display: grid;
  gap: clamp(20px, 2.2vw, 28px);
  align-content: start;
  background: rgba(255,255,255,.045);
  border: 1px solid rgba(255,255,255,.12);
  transition: background .5s var(--ease), border-color .5s var(--ease);
}
.api__card:hover { border-color: rgba(255,158,44,.4); background: rgba(255,255,255,.07); }

.api__head { display: grid; gap: 10px; }
.api__head .body-sm { color: rgba(255,255,255,.66); max-width: 44ch; }

.api__badge {
  justify-self: start;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  background: rgba(255,158,44,.16);
  color: var(--amber);
}

.api__chips { display: flex; flex-wrap: wrap; gap: 8px; }
/* The chip is a light-surface component by default; on this ground it needs
   the same inversion the pricing add-ons used to apply */
.api__card .chip {
  background: rgba(255,255,255,.05);
  border-color: rgba(255,255,255,.13);
  color: rgba(255,255,255,.82);
}
.api__card .chip:hover { border-color: rgba(255,158,44,.55); box-shadow: none; }

/* ---- the endpoints ---- */
/* Addresses, so they are set in mono and allowed to wrap rather than being
   truncated — a URL you cannot read in full proves nothing. The 1px grid gap
   over a light background is what draws the dividing rules. */
.ends {
  display: grid;
  gap: 1px;
  background: rgba(255,255,255,.12);
  border-radius: var(--r);
  overflow: hidden;
}
.end {
  display: grid;
  gap: 5px;
  padding: 14px 16px;
  background: rgba(10,10,10,.42);
}
.end__k {
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(255,255,255,.42);
  font-style: normal;
}
.end__v {
  font-family: var(--mono);
  font-size: .84rem;
  font-weight: 400;
  color: var(--paper);
  overflow-wrap: anywhere;
}
.end__v--tok { color: var(--amber); }
.end__note { font-size: .76rem; color: rgba(255,255,255,.42); }
.end--key { background: rgba(255,158,44,.08); }

/* ---- what it reaches ---- */
.reach { display: grid; gap: 18px; }
.reach__g { display: grid; gap: 9px; }
.reach__k {
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(255,255,255,.62);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
/* The roadmap flag rides inside its own label rather than floating loose, so
   it can never be read as applying to the group above it */
.reach__k em {
  font-style: normal;
  font-size: .92em;
  letter-spacing: .1em;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  border: 1px dashed rgba(255,255,255,.3);
  color: rgba(255,255,255,.46);
}
.reach__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.reach__tail { font-size: .86rem; line-height: 1.55; color: rgba(255,255,255,.6); max-width: 46ch; }
.reach__g--soon .chip { color: rgba(255,255,255,.55); }

.api__foot {
  font-size: .84rem;
  line-height: 1.6;
  color: rgba(255,255,255,.42);
  max-width: 78ch;
  padding-top: 4px;
}

/* ============================================================
   15. TESTIMONIALS  — adapted from Realtab
   ============================================================ */
.quotes { overflow: hidden; }
.quotes .marquee__group { gap: 18px; padding-right: 18px; align-items: stretch; }

.quote {
  width: clamp(290px, 34vw, 400px);
  flex: none;
  display: grid;
  gap: 20px;
  align-content: space-between;
  padding: clamp(24px, 2.6vw, 32px);
  border-radius: var(--r-lg);
  background: rgba(255,255,255,.045);
  border: 1px solid rgba(255,255,255,.11);
  transition: background .5s var(--ease), border-color .5s var(--ease);
}
.quote:hover { background: rgba(255,255,255,.075); border-color: rgba(255,158,44,.34); }

/* A quote glyph, not stars — these are use cases, and a star row would read
   as a rating. Swap in stars only once these are real customer testimonials. */
.quote__mark { color: var(--amber); opacity: .85; }
.quote__mark svg { width: 21px; height: auto; }

.quote__t {
  font-size: 1.02rem;
  line-height: 1.54;
  letter-spacing: -.012em;
  color: rgba(255,255,255,.9);
}

.quote__by {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,.1);
}
.quote__av {
  width: 38px; height: 38px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(255,158,44,.14);
  color: var(--amber);
  font-size: .82rem;
  font-weight: 600;
  flex: none;
}
.quote__nm { font-size: .9rem; font-weight: 500; }
.quote__rl { font-size: .8rem; color: rgba(255,255,255,.46); }

/* ============================================================
   16. PRICING
   ============================================================ */
/* Concentric ripple behind the cards — pure CSS, masked to a soft pool so the
   rings never reach the section edges and read as a hard pattern. */
.ripple {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.ripple::before,
.ripple::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 46%;
  width: min(1500px, 155vw);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: repeating-radial-gradient(circle at 50% 50%,
    rgba(255,255,255,.055) 0 1px,
    rgba(255,255,255,0) 1px 58px);
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 12%, rgba(0,0,0,.5) 48%, transparent 72%);
  mask-image: radial-gradient(circle at 50% 50%, #000 12%, rgba(0,0,0,.5) 48%, transparent 72%);
}
/* Second, amber-tinted ring set, offset and slower — gives the pattern depth */
.ripple::after {
  width: min(1050px, 118vw);
  background: repeating-radial-gradient(circle at 50% 50%,
    rgba(255,158,44,.10) 0 1px,
    rgba(255,158,44,0) 1px 42px);
  animation: rippleOut 14s var(--ease-io) infinite;
}
@keyframes rippleOut {
  0%   { transform: translate(-50%, -50%) scale(.86); opacity: .25; }
  55%  { opacity: .8; }
  100% { transform: translate(-50%, -50%) scale(1.16); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ripple::after { animation: none; opacity: .5; }
}

.plans { position: relative; z-index: 1; display: grid; gap: 16px; }
@media (min-width: 720px)  { .plans { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .plans { grid-template-columns: repeat(4, 1fr); } }

/* Flex column rather than grid, so the top-up line and the button below it can
   be pushed to the bottom with an auto margin and stay on one baseline across
   all four cards — grid's align-content:start leaves the spare height outside
   any row, where an auto margin cannot reach it. */
.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: clamp(24px, 2.5vw, 30px);
  border-radius: var(--r-lg);
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.11);
  transition: transform .5s var(--ease), border-color .5s var(--ease), background .5s var(--ease);
}
.plan:hover { transform: translateY(-5px); border-color: rgba(255,255,255,.24); }
.plan--pop { border-color: var(--amber); background: rgba(255,158,44,.055); }
.plan--pop:hover { border-color: var(--amber); }

.plan__flag {
  position: absolute;
  top: -1px; right: 20px;
  transform: translateY(-50%);
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  background: var(--amber);
  color: var(--ink);
  font-weight: 500;
}

.plan__nm {
  font-size: .78rem;
  font-family: var(--mono);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--tx-faint);
}
.plan__pr { display: flex; align-items: baseline; gap: 5px; }
.plan__pr b {
  font-size: clamp(2.1rem, 3vw, 2.7rem);
  font-weight: 500;
  letter-spacing: -.045em;
  line-height: 1;
}
.plan__pr span { font-size: .82rem; color: var(--tx-faint); }
.plan__cr {
  font-size: .88rem;
  color: var(--amber);
  font-weight: 500;
}
.plan__ls { display: grid; gap: 9px; }
.plan__ls li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: start;
  font-size: .875rem;
  color: rgba(255,255,255,.62);
}
.plan__ls svg { width: 13px; height: 13px; margin-top: .38em; color: var(--amber); flex: none; }
.plan .btn { width: 100%; }

/* The top-up line. Ruled off from the feature list rather than joining it,
   because it answers a different question — not what the plan includes, but
   what happens once you have used it up. Amber on the two tiers where the
   answer is a discount, so the difference reads while scanning the four. */
.plan__extra {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,.12);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1.5;
  color: rgba(255,255,255,.5);
}
.plan__extra--deal { color: var(--amber); }

/* ============================================================
   17. FAQ  — adapted from Fabrica
   ============================================================ */
.faq-list { border-top: 1px solid var(--line); }

.faq {
  border-bottom: 1px solid var(--line);
}
.faq__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  text-align: left;
  padding-block: clamp(22px, 2.4vw, 30px);
  font-size: clamp(1.02rem, 1.55vw, 1.28rem);
  font-weight: 450;
  letter-spacing: -.02em;
  color: var(--tx);
  transition: color .4s var(--ease), padding-left .5s var(--ease);
}
.faq__q:hover { color: var(--amber); padding-left: 10px; }

.faq__sign {
  position: relative;
  width: 34px; height: 34px;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--line);
  transition: background .45s var(--ease), border-color .45s var(--ease), transform .5s var(--ease);
}
.faq__sign::before, .faq__sign::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 12px; height: 1.5px;
  background: currentColor;
  transform: translate(-50%,-50%);
  transition: transform .45s var(--ease), opacity .3s ease;
}
.faq__sign::after { transform: translate(-50%,-50%) rotate(90deg); }
.faq[open] .faq__sign { background: var(--amber); border-color: var(--amber); color: var(--ink); transform: rotate(180deg); }
.faq[open] .faq__sign::after { opacity: 0; }

.faq__a {
  overflow: hidden;
  height: 0;
  transition: height .5s var(--ease);
}
.faq__a > div {
  padding-bottom: clamp(22px, 2.4vw, 30px);
  padding-right: clamp(0px, 8vw, 130px);
  font-size: .97rem;
  line-height: 1.66;
  color: var(--tx-mute);
}

/* ============================================================
   18. CONTACT  — adapted from Fabrica
   ============================================================ */
.contact { position: relative; overflow: hidden; }
/* `overflow: hidden` has to stay — the orb is wider than the viewport on a
   phone (120vw) and would otherwise push horizontal page scroll. So the orb
   is made to finish inside the section rather than be cut by it:
     · bounded by `inset` instead of a locked 1:1 aspect-ratio, which used to
       run it 232px past the section and into a hard edge against the FAQ
     · an ellipse, so a wide short box still fades evenly in both axes
     · and a mask that tapers the last third to nothing, which holds no matter
       how the section's height changes with copy or viewport.
   Belt and braces deliberately: the clip is invisible only while the orb is
   already transparent everywhere it meets it. */
.contact__glow {
  position: absolute;
  left: 50%; top: 6%;
  width: min(900px, 120vw);
  height: 74%;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at 50% 50%,
    rgba(255,158,44,.17) 0%,
    rgba(255,158,44,.07) 34%,
    rgba(255,158,44,0) 68%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 58%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 58%, transparent 100%);
  pointer-events: none;
}
.contact__inner { position: relative; z-index: 1; display: grid; gap: clamp(40px, 5vw, 72px); }
@media (min-width: 980px) { .contact__inner { grid-template-columns: 1fr 1fr; gap: clamp(48px, 6vw, 96px); } }

.contact__title {
  font-size: clamp(2.6rem, 6.6vw, 5.4rem);
  line-height: .96;
  letter-spacing: -.045em;
  font-weight: 500;
}
.contact__meta { display: grid; gap: 20px; margin-top: 34px; }
.cmeta { display: grid; gap: 4px; }
.cmeta__k {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--tx-faint);
}
.cmeta__v { font-size: 1rem; }
.cmeta__v a:hover { color: var(--amber); }

.form { display: grid; gap: 16px; align-content: start; }
.field { display: grid; gap: 8px; }
@media (min-width: 560px) { .form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } }

.field label {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--tx-faint);
}
.field input, .field textarea, .field select {
  width: 100%;
  padding: 14px 16px;
  border-radius: var(--r);
  background: rgba(255,255,255,.04);
  border: 1px solid var(--line);
  color: var(--tx);
  font-size: .95rem;
  transition: border-color .4s var(--ease), background .4s var(--ease);
}
.field select { appearance: none; cursor: pointer; }
.field select option { background: var(--ink); color: var(--paper); }
.field textarea { resize: vertical; min-height: 128px; }
.field input::placeholder, .field textarea::placeholder { color: rgba(255,255,255,.28); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--amber);
  background: rgba(255,255,255,.07);
}

.form__note { font-size: .8rem; color: var(--tx-faint); }
.form__note a { color: var(--amber); }
.hp { position: absolute; left: -9999px; opacity: 0; pointer-events: none; }

.form__ok {
  display: none;
  padding: 15px 18px;
  border-radius: var(--r);
  background: rgba(255,158,44,.11);
  border: 1px solid rgba(255,158,44,.35);
  font-size: .9rem;
  color: var(--amber);
}
.form__ok.on { display: block; }

/* ============================================================
   19. FOOTER  — adapted from Spartan AI
   ============================================================ */
/* The page scrolls over the footer, which sits fixed behind everything and is
   revealed only at the very bottom. `main` carries a solid background and
   reserves matching space so nothing shows through early. */
main {
  position: relative;
  z-index: 2;
  background: var(--bone);
  margin-bottom: var(--footer-h);
}

.footer {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 0;
  height: var(--footer-h);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  /* Warm, to match the sand photograph behind it. Only ever seen in the
     moment before the image decodes, so it is the photo's own dark tone
     rather than a colour of its own. */
  background: #2A1206;
  color: var(--tx-inv);
  --tx: var(--tx-inv);
  --tx-mute: var(--tx-inv-mute);
  --tx-faint: var(--tx-inv-faint);
  --line: var(--line-inv);
  overflow: hidden;
}

/* Footer content sits directly on the photograph */
.footer__inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.footer__top {
  position: relative;
  z-index: 2;
  /* Trimmed alongside the taller footer — on a short laptop window the height
     alone does not buy enough room to clear the wordmark. */
  padding-top: clamp(40px, 4.4vw, 64px);
  padding-bottom: clamp(30px, 3.4vw, 46px);
  display: grid;
  gap: 40px;
}
@media (min-width: 900px) {
  .footer__top { grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; }
}
/* Below that the three link columns hold two abreast rather than stacking into
   one long ribbon — it keeps the footer short enough that the wordmark behind
   it still gets air. The brand block takes the full width above them. */
@media (max-width: 899.98px) {
  .footer__top {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 26px 24px;
  }
  .footer__brand { grid-column: 1 / -1; }
  .fcol { gap: 10px; }
}
/* The footer is a fixed panel revealed at the very bottom, so its height is
   also the space `main` reserves — content taller than it is simply clipped.
   On a phone the stacked brand block plus two link rows runs past a 86vh
   panel and takes the copyright bar with it, so the reveal gets more room. */
@media (max-width: 559.98px) {
  :root { --footer-h: clamp(600px, 96vh, 820px); }
  .footer__bar { padding-block: 16px; }
}

.footer__brand { display: grid; gap: 16px; align-content: start; max-width: 34ch; }
.footer__brand .brand { color: var(--paper); }
/* Sitting on photography rather than a flat panel — a soft shadow keeps every
   line readable without needing an opaque backing block */
.footer__inner { text-shadow: 0 1px 14px rgba(38,16,4,.7); }

.fcol { display: grid; gap: 12px; align-content: start; }
.fcol__h {
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(255,255,255,.62);
}
.fcol a {
  font-size: .92rem;
  color: rgba(255,255,255,.86);
  transition: color .35s var(--ease), transform .35s var(--ease);
  display: inline-block;
}
.fcol a:hover { color: var(--amber); transform: translateX(4px); }

/* Sits directly under the link columns, in the darkened upper band — pushing it
   to the bottom would land it on the bright NGARO letters and make it unreadable.
   The wordmark then closes the page uninterrupted. */
.footer__bar {
  position: relative;
  z-index: 2;
  padding-block: 20px;
  border-top: 1px solid rgba(255,255,255,.18);
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: space-between;
  align-items: center;
  font-size: .82rem;
  color: rgba(255,255,255,.68);
  text-shadow: 0 1px 12px rgba(38,16,4,.65);
}
.footer__bar nav { display: flex; flex-wrap: wrap; gap: 20px; }
.footer__bar a:hover { color: var(--amber); }

/* The sand photograph fills the whole footer as its backdrop */
.footer__art {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.footer__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Anchored to the bottom so the ridge of sand — and the seedlings on it —
     stay in frame as the panel's height changes with the viewport */
  object-position: center bottom;
}
/* Legibility only — a soft darkening of the upper sky where the links sit,
   deliberately not an opaque block, so the photo reads the whole way through.
   Warm-toned: a neutral or green scrim over this much orange greys it out. */
.footer__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    rgba(34,13,3,.8) 0%, rgba(34,13,3,.62) 26%,
    rgba(34,13,3,.3) 46%, rgba(34,13,3,0) 66%);
  pointer-events: none;
}

/* ---- the wordmark ---- */
/* Spans the page and scales with it, without a single breakpoint: the width of
   a line of text is proportional to its font-size, and a vw font-size is
   proportional to the viewport — so one tuned value holds at every width. The
   letter-spacing has to be in em for the same reason; a px value would drift
   the fit as the type grew.

   It sits behind the footer content (z-index 1 against .footer__inner's 2) and
   bleeds a little past the bottom edge, which is what stops it reading as a
   word sitting in a box rather than as part of the photograph. */
.footer__word {
  position: absolute;
  left: 50%;
  bottom: -1.2vw;
  z-index: 1;
  transform: translateX(-50%);
  font-size: 29.2vw;
  line-height: .74;
  font-weight: 600;
  letter-spacing: -.038em;
  white-space: nowrap;
  color: rgba(255,255,255,.93);
  text-shadow: 0 2px 40px rgba(38,16,4,.4);
  pointer-events: none;
  user-select: none;
}

/* ============================================================
   20. SCROLL REVEALS
   ============================================================ */
/* Scoped to .js — without it every revealed element would stay invisible */
.js [data-rise] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .82s var(--ease), transform .82s var(--ease);
  transition-delay: var(--d, 0ms);
}
.js [data-rise].in { opacity: 1; transform: none; }

.js [data-clip] {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.05s var(--ease-io);
  transition-delay: var(--d, 0ms);
}
.js [data-clip].in { clip-path: inset(0 0 0 0); }

/* Progress bar */
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  z-index: 300;
  transform-origin: left;
  transform: scaleX(0);
  background: var(--amber);
  pointer-events: none;
}

/* ============================================================
   21. POINTER
   ============================================================ */
/* Every rule here is gated on .cur-on, which only cursor.js sets, and only
   after it has a replacement on screen. Nothing below can hide the native
   cursor on its own. */
html.cur-on, html.cur-on * { cursor: none; }
/* The I-beam is load-bearing — it is how you know text is editable. These
   come after the blanket rule above and win on source order. */
html.cur-on input,
html.cur-on textarea,
html.cur-on select,
html.cur-on [contenteditable="true"] { cursor: auto; }

.cur {
  position: fixed;
  top: 0; left: 0;
  z-index: 10000;                 /* over the loader, the curtain and the nav */
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s var(--ease);
}
.cur.is-awake { opacity: 1; }
.cur.is-hidden { opacity: 0; }    /* over a text field, where the real one returns */

.cur__dot,
.cur__echo {
  position: absolute;
  top: 0; left: 0;
  border-radius: 50%;
  background: var(--amber);
  will-change: transform;
  /* The transform is written every frame by JS and must not be eased, or the
     dot lags the pointer. Only the shape change is animated. */
  margin: -4px 0 0 -4px;
  width: 8px; height: 8px;
}

.cur__dot {
  transition: width .28s var(--ease), height .28s var(--ease),
              margin .28s var(--ease), background-color .28s var(--ease),
              border-color .28s var(--ease), opacity .2s var(--ease);
  border: 0 solid var(--amber);
}

/* Over anything clickable the dot hollows out and opens into a ring, on the
   same centre — so the point you are aiming with never moves. */
.cur.is-active .cur__dot {
  width: 30px; height: 30px;
  margin: -15px 0 0 -15px;
  background: transparent;
  border-width: 1.5px;
}
/* Only opacity on press — the transform belongs to the JS, every frame */
.cur.is-down .cur__dot { opacity: .55; }

/* The echo. Each one is smaller, fainter and further behind than the last;
   three is enough to read as a trail and few enough to stay quiet. */
.cur__echo {
  width: 6px; height: 6px;
  margin: -3px 0 0 -3px;
  opacity: calc(.42 - var(--i) * .12);
}
.cur__echo:nth-child(2) { width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px; }
.cur__echo:nth-child(3) { width: 4px; height: 4px; margin: -2px 0 0 -2px; }
/* The trail is decoration; over a target it would blur the ring's centre */
.cur.is-active .cur__echo { opacity: 0; transition: opacity .2s var(--ease); }

/* ============================================================
   22. REDUCED MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .marquee__track { animation: none; }
  .js [data-rise] { opacity: 1; transform: none; }
  .js [data-clip] { clip-path: none; }
  .proof__text .w { color: var(--ink); }
}
