/* Design changes for 'Koeia website', loaded last on every page. */

/* 1. THE HERO SITS IN THE MIDDLE OF THE FIRST SCREEN.
   The hero already fills the first screen (components.css), but it stacked
   from the top: the lead took a small fixed margin and the orbit's
   margin-top:auto swallowed all the free space, so the heading rode up
   under the KOEIA word mark. The orbit is decoration (aria-hidden), so it
   leaves the flow and is pinned to the hero's foot behind the text; the
   heading, promise and buttons are then centred as one block in what is
   left. The hero starts at the top of the page (the header floats over it),
   so it takes the whole screen, not the screen minus the header: then the
   middle of the hero IS the middle of the screen. The padding keeps the
   block clear of the top logo at any height. */
body .landing__hero {
  --hero-pad: clamp(56px, 9svh, 96px);
  min-height: 100svh;
  justify-content: center;
  /* 4. AND A LITTLE ABOVE THE MIDDLE: the block's centre at 40% of the
     screen, not 50%. Centring between unequal paddings puts the centre at
     (top + (H - bottom)) / 2; a bottom 20svh deeper than the top gives
     exactly 0.4·H, at every height, with no offset to keep in step. It also
     lifts the buttons off the orbit's outer ring, whose icons ride past
     them. */
  padding-block: var(--hero-pad) calc(var(--hero-pad) + 20svh);
}

body .landing__hero .landing__lead {
  margin-top: 0;
}

body .landing__hero > :not(.orbit-well) {
  position: relative;
  z-index: 1;
}

body .landing__hero .orbit-well {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  z-index: 0;
  /* The icons ride the outer ring, and its crest is the well's top edge.
     services-v3 lets the well grow to 48svh, which brought the crest up to
     the buttons once the block sat at 40%. At 36svh (30svh on short
     screens) the crest stays at least half an icon plus a gap below them. */
  height: min(calc(var(--size) / 2 + 32px), 36svh);
}

@media (max-height: 640px) {
  body .landing__hero .orbit-well {
    height: min(calc(var(--size) / 2 + 32px), 30svh);
  }
}

@media (max-width: 720px) {
  body .landing__hero {
    --hero-pad: 64px;
    min-height: 100svh;
  }
}

/* 2. THE HERO IS SET LIKE AGENT BASE'S AS THE NIX PROTOTYPE SHOWS IT
   (prototypes/nix-website/layer.css, html.ab-blank .voice__lead and
   .voice__hero-sub), not the base view's billboard: a sentence that
   whispers — 300 weight, 34px on a phone rising to 46px, in a 640px column —
   over a 15px promise in a 420px column. Four pixels over the other big
   titles at every width: the same curve as theirs, lifted by a constant. */
body .landing__hero .landing__lead {
  max-width: 640px;
  margin-inline: auto;
  font-size: clamp(34px, calc(4.2vw + 4px), 46px);
  line-height: 1.15;
  letter-spacing: -0.015em;
  font-weight: 300;
}

/* Spanish's first line, «Preparamos negocios», is 8.85em long: at 34px it
   needs 301px and a 320px phone gives the column 272, so it would break into
   three lines. Under ~362px its floor follows the window (9.4vw) instead,
   just enough to keep two; from there up it is the same 34 → 46px. */
html[lang="es"] body .landing__hero .landing__lead {
  font-size: clamp(min(34px, 9.4vw), calc(4.2vw + 4px), 46px);
}

body .landing__hero .landing__text--intro {
  text-wrap: balance;
  max-width: 420px;
  margin: 18px auto 0;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 300;
}

/* 5. EVERY BIG TITLE ON THE LANDING SPEAKS AT THE HERO'S SIZE. services-v3
   sets its display tier — the creed's lines, the four steps, the diagnostic's
   heading, its questions and the plans' heading — at clamp(28px, 4.6vw, 46px)
   and 400, a size above the hero once change 3 brought the hero down to
   ab-blank's whisper. They take the hero's type here, in one rule. Layout is
   theirs: alignment and margins are not touched, and the 640px measure goes
   only on the ones set centred (the steps are set flush left and keep their
   column). Eyebrows, the step numbers, the plan pills and card titles are
   small type and stay as they are. */
body :is(.creed__line, .stop__t, .landing__block .landing__headline) {
  font-size: clamp(30px, 4.2vw, 42px);
  line-height: 1.15;
  letter-spacing: -0.015em;
  font-weight: 300;
}

body .creed__line,
body .landing__block .landing__headline {
  max-width: 640px;
}


/* 6. THE CREED'S PINNED STAGE IS THE PAGE ITSELF, NOT A GREY BOX. While the
   creed is live (every width since scope 3) services-v3 paints its stage --nix-panel, a flat
   rgb(20,21,22) over a 1080px box, so the road that comes up under the last
   sentence stays hidden. This page is not painted --nix-panel: the body is the
   Blank's vertical gradient, fixed to the window (blank.css), so the flat box
   showed its edges — lighter than the page above it, darker below, and cut off
   at both sides.

   SO THE STAGE IS TRANSPARENT, and the page's gradient shows through it from
   the one place it lives: the body, which is never transformed. A first
   version painted the stage with that same gradient, attachment fixed — but a
   fixed background is only fixed to the window while no ancestor carries a
   transform or a filter, and change 11's depth scales and blurs #page; the
   gradient then laid itself out against the stage's own box and the box came
   back. Covering the road was never what the paint did here: the ladder sits
   later in the document and paints over the stage where they meet (measured
   in change 6), so there is nothing behind the stage for an opaque one to
   hide. No border, radius or shadow is set on the creed or its stage. */
body .creed.is-live .creed__stage {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* 13. THE PLANS ARE A SECTION OF THE PAGE, not the verdict of a quiz (the
   quiz and its form are gone). The same heading, the same two lines and the
   same two cards, in the column the verdict gave them: 880px, centred, a
   --space-3 between the parts. The cards keep services-v3's own styles; with
   no recommendation neither is lifted over the other. */
.plans-block__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: min(880px, 100%);
  margin: 0 auto;
  text-align: center;
}

/* 11. EACH STEP IN DETAIL, WITH ECH0'S DEPTH. A quiet outline pill under
   each step opens that step's panel (a modal <dialog> after </main>, see
   index.html; opened by layer.js). The page steps back behind it the way the
   Blank's graph does for a memory (prototypes/nix-website/layer.css,
   .echo-graph.is-open): smaller, blurred, dimmer — blurred deeper here, so
   the panel reads as the only thing in front. The panel arrives like the
   memcard: from 14px below and a touch small, into place. */
.stop__more {
  display: inline-flex;
  align-items: center;
  margin: 18px 0 0;
  padding: 8px 16px;
  border: 0;
  border-radius: 999px;
  background: none;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--nix-text) 18%, transparent);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 300;
  letter-spacing: .02em;
  color: var(--nix-text);
  cursor: pointer;
  transition: background 180ms ease, box-shadow 180ms ease;
}
.stop__more:hover {
  background: color-mix(in srgb, var(--nix-text) 6%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--nix-text) 30%, transparent);
}
.stop__more:focus-visible { outline: var(--focus-ring, 2px solid currentColor); outline-offset: 3px; }

/* the page behind: everything that is not the panel. Three plain rules, not
   one :is() — :is() takes its most specific member's weight, and #page would
   have lent an id's to the logo and the menu ring, overruling their own
   transforms and transitions. The ring keeps its border-color transition. */
#page {
  transform-origin: 50% 50%;
  transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 650ms cubic-bezier(.2,.7,.2,1), opacity 650ms cubic-bezier(.2,.7,.2,1);
}
.nix-toplogo {
  transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 650ms cubic-bezier(.2,.7,.2,1), opacity 650ms cubic-bezier(.2,.7,.2,1);
}
.site-menu__trigger {
  transition: border-color var(--dur-3) ease, transform 650ms cubic-bezier(.2,.7,.2,1), filter 650ms cubic-bezier(.2,.7,.2,1), opacity 650ms cubic-bezier(.2,.7,.2,1);
}
/* .ti-chrome is the Blank's own chrome (blank.js): a fixed, window-sized layer
   carrying the menu ring that is actually drawn at the top left — the
   .site-menu__trigger beneath it measures 0×0 on this page. It recedes from
   the window's centre like the page does. */
.ti-chrome {
  transform-origin: 50% 50%;
  transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 650ms cubic-bezier(.2,.7,.2,1), opacity 650ms cubic-bezier(.2,.7,.2,1);
}
html.is-depth #page,
html.is-depth .site-menu__trigger,
html.is-depth .ti-chrome {
  transform: scale(.94);
  filter: blur(10px);
  opacity: .10;
}
/* the toplogo is centred with a translate of its own; it keeps it */
html.is-depth .nix-toplogo {
  transform: translateX(-50%) scale(.94);
  filter: blur(10px);
  opacity: .10;
}
/* 12. .10, not the Blank's .45: with no card behind the words, the page has
   to step almost all the way back for them to read. */
/* the background does not scroll while a panel is up */
html.is-held #page { overflow: hidden; }

/* the dialog is the whole window, transparent: anywhere on it that is not the
   words closes it (layer.js) */
.step-detail {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 24px;
  box-sizing: border-box;
  border: 0;
  background: transparent;
  color: var(--nix-text);
  overflow: hidden;
}
.step-detail[open] { display: flex; align-items: center; justify-content: center; }
.step-detail::backdrop { background: transparent; }

.step-detail__card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: min(520px, 100%);
  max-height: 100%;
  box-sizing: border-box;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* 12. NO CARD. The words stand on the receded page by themselves: no fill,
     no rule, no radius, no backdrop, no shadow. The padding stays, empty, so
     the text keeps the measure it had inside the card (456px). It is also
     what scrolls when the words are taller than a phone. */
  padding: 36px 32px 32px;
  border-radius: 0;
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
  opacity: 0;
  transform: translateY(14px) scale(.98);
  transition: opacity 400ms ease, transform 480ms cubic-bezier(.22,1,.36,1);
}
.step-detail.is-open .step-detail__card { opacity: 1; transform: none; }
/* it takes the focus when it opens (there is no button left to take it): no
   ring for a pointer, the site's ring for the keyboard */
.step-detail__card:focus { outline: none; }
.step-detail__card:focus-visible { outline: var(--focus-ring, 2px solid currentColor); outline-offset: 4px; }

/* the step's own pill, as on the ladder */
.step-detail__name {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--nix-chip);
  font-family: var(--font-sans);
  font-size: var(--text-2xs, 11px);
  font-weight: 500;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--nix-text-soft);
}
.step-detail__t {
  margin: 0;
  max-width: 440px;
  font-size: clamp(22px, 2.6vw, 28px);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-align: center;
  text-wrap: balance;
}
/* what we do and what you get: four short lines over a hairline */
.step-detail__list {
  list-style: none;
  margin: 8px 0 0;
  padding: 16px 0 0;
  width: 100%;
  border-top: 1px solid color-mix(in srgb, var(--nix-text) 10%, transparent);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.step-detail__list li {
  position: relative;
  padding-left: 18px;
  font-size: 15px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--nix-text);
  text-wrap: pretty;
}
.step-detail__list li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: .7em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--nix-text) 35%, transparent);
}

/* on a phone the panel takes nearly the whole width, and scrolls inside */
@media (max-width: 600px) {
  .step-detail { padding: 16px 12px; }
  .step-detail__card { width: 100%; padding: 24px 20px; }
}

/* reduced motion: no scale, no blur, no travel — a fade */
@media (prefers-reduced-motion: reduce) {
  #page, .nix-toplogo, .ti-chrome { transition: opacity 200ms linear; }
  .site-menu__trigger { transition: border-color var(--dur-3) ease, opacity 200ms linear; }
  html.is-depth #page,
  html.is-depth .site-menu__trigger,
  html.is-depth .ti-chrome { transform: none; filter: none; }
  html.is-depth .nix-toplogo { transform: translateX(-50%); filter: none; }
  .step-detail__card { transform: none; transition: opacity 200ms linear; }
}

/* 14. THE ANSWER ENDS ON THE NAME, AND THE PLANS FOLLOW IT.
   The relay's last screen is KOEIA, set the way Agent Base sets ECH0 on its
   own screen (prototypes/nix-website/layer.css, .voice__name-word): the
   header's light, wide capitals — the same family and .14em tracking as the
   KOEIA in the header — at the size of a title. text-indent matches the
   tracking so the word sits on its centre, not .14em left of it. It is a
   .creed__line like the others, so it arrives with the same relay. */
body .creed__line.creed__word {
  max-width: none;
  margin-inline: auto;
  font-size: clamp(64px, 11vw, 160px);
  font-weight: 200;
  line-height: 1;
  letter-spacing: .14em;
  text-indent: .14em;
  white-space: nowrap;
}

/* The plans start right under it: no heading, the cards first, and the
   section does not reserve the 80svh a one-sentence block wants. While the
   answer is pinned, the plans are pulled up under its last screen the way
   the ladder is pulled under the creed's (services-v3, .creed.is-live +
   #ladder), so the cards rise into the space below the name instead of
   waiting half a screen behind it. */
#plans {
  min-height: 0;
  justify-content: flex-start;
}
/* 36: and down again by 48-80px, so the toggle that now heads the plans
   does not sit right under the name */
.creed--answer.is-live + #plans {
  margin-top: calc((100svh - 2 * var(--shell-gap)) * -0.35 + clamp(48px, 7svh, 80px));
}
.plans-block__inner { gap: var(--space-4); }
.plans-block__inner .plans { margin-top: 0; }

/* 16. Nothing under the cards any more: the section ends on them, and its
   bottom margin closes from the 180px a section ends on to what the page
   needs before its foot. */
#plans { margin-bottom: clamp(48px, 6vw, 80px); }
/* Flat (a phone with reduced motion, or no script: nothing pinned) the answer keeps the 200px a
   section ends on, which put a screen's worth of nothing between the name and
   the cards. It closes to what the pinned version leaves: 40–64px. */
.creed--answer:not(.is-live) {
  margin-bottom: clamp(40px, 8vw, 64px);
}

/* 15. KOEIA ARRIVES ALONE, AND OUT OF FOCUS. On every other screen of the
   relay the sentence just left stays behind as a ghost (.is-past: .28, 6px
   blur) under the one arriving. Under the name that read as two things
   crossing. So, on the name's screen only, it is a sequence: every sentence
   before it leaves completely (to 0, in 320ms), and only then the name comes
   up out of the blur.

   The appearance is ECH0's: the depth that ECH0's story words come out of as
   they light (prototypes/nix-website/layer.js ~1220: blur 6px × what is left
   to light, scale .94 → 1, opacity rising) played on the timing ECH0's own
   name enters on (the Blank's cascade, .ti-drop in nix-website/layer.css:
   520ms, cubic-bezier(.22,1,.36,1)). Reduced motion: the same sequence, a
   fade only. */
@keyframes koeia-appear {
  from { opacity: 0; filter: blur(6px); transform: scale(.94); }
  to   { opacity: 1; filter: none; transform: none; }
}
@keyframes koeia-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* AND IT IS READ LEFT TO RIGHT: K, O, E, I, A, each with that same
   appearance, 100ms apart, so the name sweeps in rather than landing as a
   block. The letters are spans (aria-hidden; the word is role="img" named
   "Koeia"), inline-blocks so each can scale; the word's tracking and the
   text-indent that centres it are untouched, and so is where each letter
   stands. The word itself is shown at once — the letters are what appear. */
.creed__word > span {
  display: inline-block;
  /* text-indent is inherited, and an inline-block is a block of its own:
     left alone, every letter would be indented .14em and the word would
     grow by five of them */
  text-indent: 0;
}
/* and the font kerns K and O tighter than their boxes: in separate spans that
   pair loses it (measured: −0.0453em at every size), so the K gives it back */
.creed__word > span:first-child { margin-right: -0.0453em; }

/* pinned (every width but a phone asking for reduced motion): the sentences go, then the letters, one by one */
.creed--answer.is-live:has(.creed__word.is-now) .creed__line:not(.creed__word) {
  opacity: 0;
  visibility: hidden;
  transition: opacity 320ms ease, filter 320ms ease, transform 320ms ease, visibility 0s linear 320ms;
}
.creed--answer.is-live .creed__word.is-now { transition: none; }
.creed--answer.is-live .creed__word.is-now > span {
  animation: koeia-appear 520ms cubic-bezier(.22,1,.36,1) calc(320ms + var(--i, 0) * 100ms) both;
}

/* flat (a phone with reduced motion): the name waits unseen until it reaches the screen
   (layer.js adds .is-waiting, then .is-arrived), then sweeps in the same way */
.creed--answer:not(.is-live) .creed__word.is-waiting > span { opacity: 0; }
.creed--answer:not(.is-live) .creed__word.is-arrived > span {
  animation: koeia-appear 520ms cubic-bezier(.22,1,.36,1) calc(var(--i, 0) * 100ms) both;
}

/* reduced motion: the same order of events, but all five letters together,
   and a fade */
@media (prefers-reduced-motion: reduce) {
  .creed--answer.is-live:has(.creed__word.is-now) .creed__line:not(.creed__word) {
    filter: none;
    transition: opacity 320ms ease, visibility 0s linear 320ms;
  }
  .creed--answer.is-live .creed__word.is-now > span {
    animation: koeia-fade 520ms cubic-bezier(.22,1,.36,1) 320ms both;
  }
  .creed--answer:not(.is-live) .creed__word.is-arrived > span {
    animation: koeia-fade 520ms cubic-bezier(.22,1,.36,1) both;
  }
}

/* ---- 17–18. The prices -----------------------------------------------------
   Under each plan's description, before its apps: no box of its own, just the
   card's type. The year is the headline the comparison is made on; the monthly
   way to pay it follows a step smaller, right under it, then the grey line of
   what the year buys, and the FDE training closes the block at the card's
   smallest size. */
.plan__price {
  display: flex;
  flex-direction: column;
  margin: var(--space-3) 0 0;
}
.plan__amount {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 28px;
  font-weight: 300;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--nix-text);
}
/* 39. The figure reads as one number: proportional figures, so a "1" takes a
   1's width and not a 0's (the block used to ask for tabular figures, which
   left "$1 14,000" with a hole after the one), and the unit after it a step
   down and softer, so the amount is what the eye lands on. */
.plan__fig {
  font-variant-numeric: proportional-nums;
  font-feature-settings: "pnum" 1, "tnum" 0;
}
.plan__per {
  font-size: 0.6em;
  letter-spacing: 0;
  color: var(--nix-text-soft);
}
/* the small line under the figure (33): only yearly has one ("Paid upfront
   · save 5%"); quarterly leaves it empty (34). Its line is kept either way —
   min-height of one line — so flipping the toggle fades the words in and out
   of a space that is already there, and nothing under it moves. */
.plan__term {
  margin: 6px 0 0;
  min-height: 1.2em;
  line-height: 1.2;
  font-size: var(--text-xs);
  font-weight: 400;
  letter-spacing: 0.02em;
  color: var(--nix-text-soft);
}
.plan__note {
  margin: 12px 0 0;
  font-size: 13px;
  font-weight: 300;
  line-height: 1.45;
  color: var(--nix-text-soft);
  text-wrap: pretty;
}

/* Side by side, the three prices sit on one line. Each card's four parts
   (head, price, apps, button) share the grid's rows through subgrid, so a
   longer grey line in one price block no longer pushes its apps below the
   others'. The streamed lists take size containment: without it their two
   stacked copies would be the row's height instead of filling it.
   Three across from 1024px, in the section's full 1080px (about 340px a card
   at 1440, 290px at 1024); under that, one under the other. */
@media (min-width: 1024px) {
  .plans-block__inner { width: min(1080px, 100%); }
  .plans {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-rows: auto auto 1fr auto;
    row-gap: 0;
  }
  .plans .plan {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
  }
  .plans .plan__stream { contain: size; }
}
@media (max-width: 1023px) {
  .plans { grid-template-columns: minmax(0, 1fr); }
  .plan__stream { min-height: 180px; }
}

/* Ownership streams the same catalogue as Industry, half a loop behind: two
   lists moving in step side by side read as one list shown twice. Foundation
   (its own eight, a 24s loop) starts a third of the way in. */
.plan[data-plan="ownership"] .plan__stream-track { animation-delay: -25.5s; }
.plan[data-plan="foundation"] .plan__stream-track { animation-delay: -8s; }

/* ---- 20. The call to action and the questions -------------------------------
   After the plans, one line at the hero's size with the hero's button, centred
   in its own stretch of page like the answer's lines; then the questions, in
   the site's own .faq (components.css): native <details>, closed until touched,
   hairlines and no cards. Only the distance to the footer is set here. */
.koeia-cta { min-height: 64svh; }
.koeia-cta .landing__cta { justify-content: center; }
#faq { margin-bottom: clamp(48px, 6vw, 80px); }

/* ---- 28. The cards in ECH0's fill ------------------------------------------
   The plan cards and the step tiles take the card of ECH0's landing
   (prototypes/nix-website/layer.css, "The plans in the same card as the graph
   and the artifacts"): the ground's own middle colour, --ti-bg-mid (#ebebe8
   light, #141516 dark), flat — no border, no shadow, no glass. Radius as
   there: the price cards 10px, like ECH0's plans; the step tiles 20px, like
   its graph and artifacts cards. On the same fixed gradient as ECH0's, the
   fill reads against the lighter top and the darker foot of the window. */
.plans .plan,
.stop .stop__n {
  background: var(--ti-bg-mid);
  border: 0;
  box-shadow: none;
}
.plans .plan { border-radius: 10px; }
.stop .stop__n { border-radius: 20px; }

/* ---- 28b. Phones: the same motion, lighter ----------------------------------
   The step detail's depth on a phone is the move without the blur: the page
   still steps back to .94, but a 10px blur animated across the whole window
   is the most expensive thing this page asks a phone's GPU for. What the blur
   did was keep the page's words from reading through the panel's; without
   it, at .10 they do (measured: the step's title, sharp, behind the list), so
   on a phone the page goes further down instead, to .04. Desktop keeps both. */
@media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
  html.is-depth #page,
  html.is-depth .site-menu__trigger,
  html.is-depth .ti-chrome,
  html.is-depth .nix-toplogo { filter: none; opacity: .04; }
}
/* off-screen, the streams hold still (layer.js adds .is-paused) */
.plan__stream.is-paused .plan__stream-track { animation-play-state: paused; }
/* the FAQ's answer rises 6px and its chevron turns (components.css); under
   reduced motion the answer is simply there and the chevron simply flips */
@media (prefers-reduced-motion: reduce) {
  .faq__item[open] .faq__a { animation: none; }
  .faq__q::after { transition: none; }
}

/* ---- 32. The contact page -----------------------------------------------------
   contact.html and contact-sent.html, the landing's own place to ask for a
   quote or a call: the hero's title type over the hero's 15px line, in one
   centred column, and the site's own form fields under it — no card. */
.koeia-contact {
  align-items: center;
  gap: 0;
  padding-inline: 24px;
  padding-top: clamp(96px, 14svh, 160px);
  padding-bottom: clamp(48px, 6vw, 80px);
}
.koeia-contact > * { width: min(560px, 100%); }
.contact__head { text-align: center; }
.contact__title {
  max-width: 640px;
  margin: 0 auto;
  font-size: clamp(34px, calc(4.2vw + 4px), 46px);
  line-height: 1.15;
  letter-spacing: -0.015em;
  font-weight: 300;
  text-wrap: balance;
}
.contact__intro {
  max-width: 420px;
  margin: 18px auto 0;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 300;
  color: var(--nix-text-soft);
  text-wrap: balance;
}
/* the site's form spaces itself by --shell-gap, which is 0 on this shell:
   the fields would touch, so the column sets its own rhythm */
.contact__form { margin-top: var(--space-6); gap: 20px; }
.contact__form .es-form__row { gap: 20px 16px; }
.contact__form .es-field { gap: 6px; }
/* the select keeps the field's look; its arrow is a hairline chevron */
.contact__select { position: relative; display: block; }
.contact__select select { appearance: none; -webkit-appearance: none; padding-right: 40px; cursor: pointer; }
.contact__select::after {
  content: '';
  position: absolute;
  right: 16px;
  top: 50%;
  width: 7px;
  height: 7px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  opacity: .55;
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
.contact__submit { align-self: center; margin-top: var(--space-1); }
.contact__cta { justify-content: center; }
.koeia-contact--sent { justify-content: center; min-height: 100svh; padding-top: 0; }
@media (max-width: 640px) {
  .contact__form .es-form__row { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 33. Quarterly or yearly ---------------------------------------------------
   A quiet segmented pill over the cards, in colours the page already has: the
   track a 6% wash of the text colour, the chosen half filled with the text
   colour and its words in the surface's (ECH0's account choices do the same).
   "Save 5%" is a small tag that inverts with its half. */
.billing {
  align-self: center;
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--nix-text) 6%, transparent);
}
.billing__opt {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 18px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--nix-text-soft);
  font: inherit;
  font-size: 13px;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background-color 240ms ease, color 240ms ease;
}
.billing__opt[aria-checked="true"] {
  background: var(--nix-text);
  color: var(--nix-surface, var(--ti-bg-top));
}
.billing__opt:focus-visible { outline: 2px solid var(--nix-text); outline-offset: 2px; }
.billing__save {
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: color-mix(in srgb, currentColor 14%, transparent);
}
/* the figure and its line change behind a short fade and blur, in place */
.plan__price .plan__amount,
.plan__price .plan__term {
  transition: opacity 220ms cubic-bezier(.22,1,.36,1), filter 220ms cubic-bezier(.22,1,.36,1);
}
.plan__price.is-swapping .plan__amount,
.plan__price.is-swapping .plan__term {
  opacity: 0;
  filter: blur(4px);
  transition-duration: 160ms;
}
@media (prefers-reduced-motion: reduce) {
  .billing__opt { transition: none; }
  .plan__price .plan__amount, .plan__price .plan__term { transition: none; }
}
/* The answer is pinned, its stage a full screen tall, and since 14 the plans
   are pulled up under its last screen: transparent, the section still sat
   over the top of the plans and took their clicks (measured: the toggle
   answered the keyboard but not the pointer). Raising the plans instead would
   paint the cards over KOEIA where the two meet; the answer holds only
   sentences, so it lets the pointer through. */
.creed--answer.is-live { pointer-events: none; }
/* One line for the figure, always: "$30,000 / trimestre" at 28px is wider
   than a 320px phone's card, and a figure that wraps in one billing and not
   the other moves everything under it when the toggle flips. Under 420px the
   size follows the window instead (22px at 320, 28px again by 400). */
.plan__price .plan__amount { white-space: nowrap; }
/* (39: with the unit at .6em the longest, "$30,000 / trimestre", fits a
   320px card at the full 28px, so the narrow-screen step-down is gone) */

/* ---- 36. Four rows and a half ----------------------------------------------------
   Every card's apps in the same window: four rows and the top half of a fifth,
   cut by the stream's own fade so it is plain there are more. A row is a 36px
   tile and 16px under it (52px), so the window is 4 x 52 + 26 = 234px — fixed,
   on every screen, which also takes the cards down to one height. Under
   reduced motion the lists stand still on their first four and a half. */
.plans .plan__stream {
  flex: none;
  height: 234px;
  min-height: 0;
  contain: size;
}

/* ---- 40. Names and lines, no icons ------------------------------------------------
   Each row of a card's apps is the name over a short line on what it does,
   in the soft grey and a step smaller. The row keeps the icon's 36px — 18px
   for the name, 2px, 16px for the line — so the pitch is still 52px and the
   234px window still shows four rows and half a fifth. One line each: the
   lines are written to fit the narrowest card; past that they would end in
   an ellipsis rather than push the row taller. */
.plans .plan__stream-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  height: 36px;
}
.plans .plan__stream-row .plan__mod-name { font-size: 14px; line-height: 18px; }
.plans .plan__mod-desc {
  font-size: 12px;
  line-height: 16px;
  font-weight: 300;
  color: var(--nix-text-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- 41. Payment plans, a note under the cards ----------------------------------
   One quiet line, centred under the three cards: a calendar in the plans'
   own hairline stroke, the sentence in the page's soft grey, and the way to
   ask in the text colour. No box. It wraps centred on a phone. */
.plans-note {
  /* inline flow, not flex: wrapped on a phone, the icon stays at the start
     of the first line instead of standing alone above the sentence */
  margin: var(--space-1) auto 0;
  max-width: 560px;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 300;
  color: var(--nix-text-soft);
  text-align: center;
  text-wrap: balance;
}
.plans-note__icon {
  display: inline-block;
  vertical-align: -3px;
  margin-right: 6px;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.7;
}
.plans-note__link {
  margin-left: 8px;
  color: var(--nix-text);
  font-weight: 400;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  white-space: nowrap;
  transition: text-decoration-color 200ms ease;
}
.plans-note__link:hover { text-decoration-color: currentColor; }
.plans-note__link:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; border-radius: 3px; }

/* ---- 42. The contact form's focus, in the page's colours ---------------------------
   The fields asked for var(--focus-ring), which this site never defines, so
   the browser drew its own ring (the system accent, purple on this Mac). A
   field in focus now gets a hairline of the text colour around its fill, and
   the button a 2px ring of the text colour, offset — visible from the
   keyboard, quiet next to the page. */
.contact__form .es-input:focus { outline: none; }
.contact__form .es-input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--nix-text) 55%, transparent);
}
.contact__submit:focus { outline: none; }
.contact__submit:focus-visible { outline: 2px solid var(--nix-text); outline-offset: 3px; }

/* ---- 42b. One focus for the whole site ------------------------------------------
   The site's sheets ask for var(--focus-ring) and var(--focus-offset) in a
   dozen places and Koeia never defined them, so every one of those — and any
   link or button with no rule of its own (the KOEIA logo, the menu) — fell
   back to the browser's ring in the system accent. Defined here once: a 2px
   ring of the text colour, 3px out. Element-level, so any component that
   draws its own focus still wins. */
:root { --focus-ring: 2px solid var(--nix-text); --focus-offset: 3px; }
a:focus-visible,
button:focus-visible,
summary:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}
/* The Blank's Account button is drawn only while the menu is open, but with
   the menu shut it was still a Tab stop — an invisible one — and its focus
   was a change of colour. Shut, it is out of the way (visibility, after its
   fade); open, it takes the same ring as the rest. */
html:not(.is-open) .ti-profile {
  visibility: hidden;
  transition: color 250ms ease, opacity 450ms ease, visibility 0s linear 450ms;
}
html .ti-profile:focus-visible { outline: var(--focus-ring); outline-offset: 4px; border-radius: 999px; }
/* the menu's own links (Home, Request a quote) drew no ring either */
html .ti-nav a:focus-visible { outline: var(--focus-ring); outline-offset: 6px; border-radius: 4px; }

/* ---- 43. One minute read ---------------------------------------------------------
   The switch (46): centred under the hero's button; the label in the soft grey at the plans' label
   size, and the page's thin switch (ECH0's): a wash of the text colour for
   the track, the text colour for the knob, which slides across when on. */
body .landing__hero > .brief-switch { position: relative; z-index: 2; }
.brief-switch {
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 20px auto 0;
  padding: 6px 4px;
  border: 0;
  background: none;
  color: var(--nix-text-soft);
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: color 200ms ease;
}
.brief-switch:hover, .brief-switch[aria-checked="true"] { color: var(--nix-text); }
.brief-switch__track {
  position: relative;
  width: 30px;
  height: 16px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--nix-text) 14%, transparent);
  transition: background-color 300ms ease;
}
.brief-switch__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--nix-text);
  transition: translate 350ms cubic-bezier(.2,.7,.2,1);
}
.brief-switch[aria-checked="true"] .brief-switch__track { background: color-mix(in srgb, var(--nix-text) 32%, transparent); }
.brief-switch[aria-checked="true"] .brief-switch__knob { translate: 14px 0; }
.brief-switch:focus-visible { outline: var(--focus-ring); outline-offset: 4px; border-radius: 999px; }

/* The one-minute version: one paragraph, why → how → what, in the reading
   type ECH0's story uses for a passage (prototypes/nix-website, .voice__story:
   18-22px, 300, 1.55, 640px column), and the price the way ECH0's plans set it (.voice__plan-fig: the
   figure at 30px and its words at 12px in the soft grey, on one baseline),
   over the page's button. */
.brief { display: none; }
.brief__text {
  max-width: 640px;
  margin: 0 auto;
  font-size: clamp(18px, 2vw, 22px);
  font-weight: 300;
  line-height: 1.55;
  color: var(--nix-text);
  text-align: center;
  text-wrap: pretty;
}
.brief__fig {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 40px 0 0;
}
.brief__amount {
  font-size: 30px;
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.01em;
  font-variant-numeric: proportional-nums;
  color: var(--nix-text);
}
.brief__from, .brief__per {
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--nix-text-soft);
}
.brief__cta { justify-content: center; margin-top: var(--space-3); }

/* On: the hero keeps the switch and the brief; everything else is put away.
   The hero no longer dissolves as the page scrolls (nix.js writes its opacity
   inline), so a long paragraph on a phone is not fading while it is read. */
html.is-brief .brief { display: block; }
html.is-brief .landing__hero > .landing__lead,
html.is-brief .landing__hero > .landing__text--intro,
html.is-brief .landing__hero > .landing__cta,
html.is-brief .landing__hero > .orbit-well,
html.is-brief #creed,
html.is-brief #ladder,
html.is-brief #answer,
html.is-brief #plans,
html.is-brief #cta,
html.is-brief #faq { display: none; }
html.is-brief .landing__hero { opacity: 1 !important; padding-bottom: calc(var(--hero-pad) + 72px); }
/* On, the button the switch sat under is gone: the switch becomes a pill
   fixed at the foot of the window, centred, on a glass of the page's own
   ground so it reads over the text it passes; the hero keeps room under its
   last line so the pill never covers "Get a quote". */
html.is-brief body > .brief-switch {
  position: fixed;
  left: 0;
  right: 0;
  bottom: max(20px, env(safe-area-inset-bottom));
  width: max-content;
  margin: 0 auto;
  z-index: 50;
  padding: 9px 16px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ti-bg-mid) 82%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
@media (prefers-reduced-motion: reduce) {
  .brief-switch, .brief-switch__track, .brief-switch__knob { transition: none; }
}

/* ---- 44. The blog ------------------------------------------------------------------
   NIX's blog, as it is: blank.css already carries its index rows, its post
   column and the post layer, all scoped to #wrapwrap like NIX's. What NIX
   takes from blog.css — the pager's own box — is here, and so is the one
   thing Koeia adds: the two languages. Every text is written in both, side
   by side (.l-en, .l-es), and the page shows the one <html lang> names, so a
   post opened in the layer follows the switch with no script. */
html[lang="es"] .l-en,
html:not([lang="es"]) .l-es { display: none !important; }
#wrapwrap .nix-pager { display: flex; justify-content: center; gap: 12px; }
#wrapwrap .nix-pager__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm, 8px);
  text-decoration: none;
}
.nix-pager__arrow svg { width: 18px; height: 18px; }
/* The column. blank.css asks for min(640px, 100%), but shell.css's
   "main.page > *" (width:auto) outranks it, so the column took its content's
   width — a whole window of text on a post. Set here at NIX's measured post
   width (a 720px column, 672px of text) for the index and every post. */
#wrapwrap.nav-shell main.page > .website_blog.nix-col { width: min(720px, 100%); margin-inline: auto; }
/* On a phone NIX's row keeps the title on one line beside the date, ending in
   an ellipsis; Koeia's titles are sentences, and at 320px that left "Your
   opera…". Under 600px the row stacks: the whole title, then its date. */
@media (max-width: 600px) {
  #wrapwrap .nix-row { flex-direction: column; align-items: flex-start; gap: 6px; }
  #wrapwrap .nix-row .nix-row__title { white-space: normal; overflow: visible; text-overflow: clip; text-wrap: balance; }
}
