
/* =========================================================
   BLUEROOK — THE OPERATION (linear scroll funnel)
   Loads AFTER showcase.css and owns the new architecture:
   locked full-height sections, the sticky two-column
   "what we do", and the scroll-driven scenes (.fx).
   Everything pulls from tokens.css. No brand hexes here.
   ========================================================= */

.fn-body {
  /* Type now lives at :root in tokens.css, so every page renders the same. */

  /* ---- One vibrant accent. Remapping --color-accent carries it to every
     state that already meant "active" (running nodes, live pills, held slots,
     found gaps). The purely decorative uses are stripped back to Paper in the
     visual-pass block below, so the accent only ever marks state or the CTA. */
  --color-accent:      var(--color-live);
  --color-accent-glow: var(--color-live-glow);
  --color-accent-soft: rgba(255, 182, 39, 0.12);

  /* ---- Geometry & depth ---- */
  --fn-radius:    16px;
  --fn-radius-sm: 10px;
  --fn-radius-xs: 8px;
  --fn-border:    1px solid rgba(255, 255, 255, 0.08);
  --fn-shadow:    0 20px 40px rgba(0, 0, 0, 0.4);
  --fn-shadow-lg: 0 28px 60px rgba(0, 0, 0, 0.5);

  /* ---- Contrast floor. The inherited Paper tints sat at 2.6:1 against
     Midnight, which fails AA for the 11–12px mono labels they are used on.
     Raised until every label clears 4.5:1; the hierarchy still reads. ---- */
  --color-text-dim:  rgba(244, 237, 224, 0.58);
  --color-text-fade: rgba(244, 237, 224, 0.52);

  --fn-gutter: clamp(20px, 5vw, 72px);
  --fn-max: 1360px;
  --fn-rule: rgba(255, 255, 255, 0.08);
  --fn-rule-soft: rgba(255, 255, 255, 0.05);
  --fn-panel: color-mix(in srgb, var(--color-surface) 74%, transparent);
  --fn-ok: #4FB477;
  --fn-hold: #C9922F;

  /* Scene pacing: viewport-heights of scroll per step. */
  --fx-pace: 72;

  /* showcase.css sets `overflow-x: hidden` here, which forces overflow-y to
     `auto` and turns the body into a scroll container — and every sticky pin
     on this page then silently stops sticking. `clip` clips the same overflow
     without creating a scroller, so `overflow-y` stays `visible`. The whole
     locked-scene architecture depends on this one line. */
  overflow-x: clip;
  overflow-y: visible;
}

/* max-width, not width: `.fn-lock > * { width: 100% }` below has equal
   specificity and comes later, so a `width` here loses and every locked
   section renders full-bleed — which is how content ended up under the
   progress rail. */
.fn-wrap {
  width: 100%;
  max-width: var(--fn-max);
  margin-inline: auto;
  padding-inline: var(--fn-gutter);
}

/* ---------------------------------------------------------
   STRICT CENTERING
   Every major section owns a full viewport and centres in it.
   --------------------------------------------------------- */
.fn-lock {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  isolation: isolate;
  overflow-x: clip;
  overflow-y: visible;
  padding-block: clamp(88px, 12vh, 150px);
}
.fn-lock > * { width: 100%; }

.fn-kicker {
  margin: 0 0 clamp(14px, 2vh, 22px);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--color-accent);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
}

/* =========================================================
   HERO
   ========================================================= */
.fn-hero { text-align: left; }
.fn-hero__bg { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.fn-hero__plate { position: absolute; inset: 0; display: block; }
.fn-hero__plate img {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.3;
  filter: saturate(0.55) contrast(1.06);
}
.fn-hero__grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, var(--fn-rule-soft) 1px, transparent 1px),
    linear-gradient(to bottom, var(--fn-rule-soft) 1px, transparent 1px);
  background-size: clamp(56px, 7vw, 96px) clamp(56px, 7vw, 96px);
  mask-image: radial-gradient(ellipse 80% 65% at 50% 45%, #000 20%, transparent 78%);
}
.fn-hero__vignette {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 60% 50% at 22% 40%, color-mix(in srgb, var(--color-mark) 42%, transparent), transparent 70%),
    linear-gradient(to bottom, transparent 40%, var(--color-bg) 96%);
}

.fn-hero__inner {
  width: 100%;
  max-width: var(--fn-max);
  margin-inline: auto;
  padding-inline: var(--fn-gutter);
}
.fn-hero__title {
  margin: 0;
  max-width: 18ch;
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 6.4vw, 5.6rem);
  font-weight: var(--fw-light);
  line-height: 1.04;
  letter-spacing: var(--ls-tight);
  text-wrap: balance;
}
.fn-hero__title .pf-line { display: block; }
.fn-hero__title em { font-style: italic; color: var(--color-accent); }
.fn-hero__lead {
  margin: clamp(20px, 3vh, 32px) 0 0;
  max-width: 34ch;
  color: var(--color-text-muted);
  font-size: var(--fs-lead);
  line-height: var(--lh-base);
}
.fn-hero__cta { margin-top: clamp(28px, 4vh, 44px); }

/* =========================================================
   THESIS
   ========================================================= */
.fn-thesis .pf-statement { max-width: 22ch; }

/* =========================================================
   WHAT WE DO — sticky left, scrolling right
   ========================================================= */
.fn-wwd {
  position: relative;
  isolation: isolate;
  overflow-x: clip;
  overflow-y: visible;
  padding-block: clamp(80px, 10vh, 140px);
  border-top: 1px solid var(--fn-rule-soft);
}
/* `align-items: stretch` is load-bearing: the left column has to inherit
   the full row height or the sticky child inside it has nowhere to travel
   and never actually sticks. */
.fn-wwd__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(32px, 5vw, 88px);
  align-items: stretch;
}

/* Exactly one viewport tall. Any taller and sticky releases early,
   stranding the system name while its last detail is still being read. */
.fn-wwd__stick {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.fn-wwd__slides { position: relative; }
.fn-wwd__slide {
  transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out), filter 420ms var(--ease-out);
}
.fn-wwd__slide:not(.is-live) {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(14px);
  filter: blur(6px);
  pointer-events: none;
}
.fn-wwd__slide.is-live { opacity: 1; transform: none; filter: none; }

.fn-wwd__num {
  display: block;
  color: var(--color-text-fade);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: var(--ls-wide);
}
.fn-wwd__name {
  margin: 10px 0 0;
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 3.6vw, 3.5rem);
  font-weight: var(--fw-light);
  line-height: 1.06;
  letter-spacing: var(--ls-tight);
}
.fn-wwd__name em { font-style: italic; color: var(--color-accent); }
.fn-wwd__line {
  margin: 16px 0 0;
  color: var(--color-text-muted);
  font-size: 1.02rem;
}
.fn-wwd__facts {
  margin: clamp(20px, 3vh, 30px) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 9px;
  border-top: 1px solid var(--fn-rule-soft);
  padding-top: clamp(18px, 2.5vh, 26px);
}
.fn-wwd__facts li {
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
}
.fn-wwd__facts b { color: var(--color-text); font-weight: var(--fw-medium); }

.fn-wwd__bar {
  margin-top: clamp(24px, 4vh, 40px);
  height: 2px;
  background: var(--fn-rule);
}
.fn-wwd__bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--color-mark);
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
  transition: transform 180ms linear;
}

/* The tail padding buys back the viewport-height that sticky always
   gives up at the end of its containing block, so the final detail is
   centred while the system name is still pinned beside it. */
.fn-wwd__right {
  display: grid;
  gap: clamp(28px, 5vh, 64px);
  padding-block: clamp(40px, 9vh, 110px) clamp(220px, 52vh, 520px);
}
.fn-det {
  border: 1px solid var(--fn-rule-soft);
  background: var(--fn-panel);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  padding: clamp(18px, 2.4vw, 28px);
  opacity: 0.4;
  filter: blur(2px);
  transform: translateY(10px);
  transition: opacity 460ms var(--ease-out), filter 460ms var(--ease-out),
              transform 460ms var(--ease-out), border-color 460ms var(--ease-out);
}
.fn-det.is-live {
  opacity: 1;
  filter: none;
  transform: none;
  border-color: color-mix(in srgb, var(--color-text) 20%, transparent);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.42);
}
.fn-body:not(.pf-js) .fn-det { opacity: 1; filter: none; transform: none; }

.fn-det header { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.fn-det__tag {
  color: var(--color-text-fade);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: var(--ls-wide);
}
.fn-det h3 {
  margin: 0;
  font-size: clamp(1.15rem, 1.5vw, 1.45rem);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-snug);
}
.fn-det > p {
  margin: 10px 0 18px;
  max-width: 52ch;
  color: var(--color-text-muted);
  font-size: 0.95rem;
  line-height: var(--lh-base);
}

/* --- the small synthetic UIs inside each detail --- */
.fn-mini {
  border: 1px solid var(--fn-rule-soft);
  background: color-mix(in srgb, var(--color-bg) 72%, transparent);
}
.fn-mini__bar {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--fn-rule-soft);
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.fn-mini__bar b { color: var(--color-text-muted); font-weight: var(--fw-medium); }

.fn-mini__rows { display: grid; }
.fn-mini__rows > div {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 9px 12px;
  font-size: 0.84rem;
}
.fn-mini__rows > div + div { border-top: 1px solid var(--fn-rule-soft); }
.fn-mini__rows span { color: var(--color-text-dim); font-family: var(--font-mono); font-size: 0.72rem; }
.fn-mini__rows b { color: var(--color-text); font-weight: var(--fw-regular); text-align: right; }

.fn-clockrow {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr) 3.2rem;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  font-size: 0.8rem;
}
.fn-clockrow + .fn-clockrow { border-top: 1px solid var(--fn-rule-soft); }
.fn-clockrow span { color: var(--color-text-muted); }
.fn-clockrow i {
  height: 5px;
  background: color-mix(in srgb, var(--color-mark) 80%, var(--color-text));
  transform: scaleX(var(--w, 0));
  transform-origin: left center;
}
.fn-clockrow b { font-family: var(--font-mono); font-size: 0.76rem; text-align: right; color: var(--color-text); }
.fn-clockrow.is-bad i { background: color-mix(in srgb, var(--color-text) 24%, transparent); }
.fn-clockrow.is-bad b, .fn-clockrow.is-bad span { color: var(--color-text-fade); }

.fn-checks { margin: 0; padding: 10px 12px; list-style: none; display: grid; gap: 8px; }
.fn-checks li {
  position: relative;
  padding-left: 24px;
  color: var(--color-text-muted);
  font-size: 0.84rem;
}
.fn-checks li::before {
  content: "";
  position: absolute;
  left: 4px; top: 0.42em;
  width: 9px; height: 5px;
  border-left: 1.5px solid var(--fn-ok);
  border-bottom: 1.5px solid var(--fn-ok);
  transform: rotate(-45deg);
}

.fn-spec { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.fn-spec > div { padding: 14px 10px; text-align: center; }
.fn-spec > div + div { border-left: 1px solid var(--fn-rule-soft); }
.fn-spec strong {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.4vw, 2.1rem);
  font-weight: var(--fw-light);
  line-height: 1;
}
.fn-spec span {
  display: block;
  margin-top: 6px;
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.fn-audit { margin: 0; padding: 6px 0; list-style: none; }
.fn-audit li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  font-size: 0.84rem;
  color: var(--color-text-muted);
}
.fn-audit li + li { border-top: 1px solid var(--fn-rule-soft); }
.fn-audit li span {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.fn-audit li[data-own="sys"] span { color: var(--fn-ok); }
.fn-audit li[data-own="you"] span { color: var(--color-text-dim); }
.fn-audit li[data-own="none"] { color: var(--color-text); }
.fn-audit li[data-own="none"] span { color: var(--color-accent); }

/* =========================================================
   SCENES (.fx) — sticky pin + scroll-driven state
   ========================================================= */
.fx {
  position: relative;
  isolation: isolate;
  overflow-x: clip;
  overflow-y: visible;
}
.fx__track { min-height: calc(100svh + (var(--fx-len, 4) * var(--fx-pace) * 1svh)); }
/* Height, not min-height: a pin taller than the viewport can never be
   scrolled to the bottom of, so every scene has to fit inside one screen. */
.fx__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* Asymmetric on purpose: the top padding has to clear the fixed nav,
   the bottom one only has to breathe. */
.fx__inner {
  display: grid;
  gap: clamp(14px, 2.4vh, 30px);
  align-content: center;
  /* The nav is a fixed ~86px bar, so the top inset is near-constant rather
     than proportional — a vh-scaled value slid section kickers under the
     logo on short screens. */
  padding-block: clamp(96px, 9vh, 118px) clamp(36px, 5vh, 80px);
}
.fx__head { max-width: 62ch; }
.fx__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 3.6vw, 3.3rem);
  font-weight: var(--fw-light);
  line-height: 1.06;
  letter-spacing: var(--ls-tight);
  text-wrap: balance;
}
.fx__title em { font-style: italic; color: var(--color-accent); }
/* Reserves two lines so a caption swap never nudges the console below it. */
.fx__cap {
  margin: 14px 0 0;
  min-height: 3.2em;
  max-width: 48ch;
  color: var(--color-text-muted);
  font-size: 1rem;
  line-height: var(--lh-base);
  transition: opacity 260ms var(--ease-out);
}
.fx__cap.is-swap { opacity: 0; }

/* =========================================================
   THE SYSTEM FLOOR — n8n canvas
   ========================================================= */
/* The canvas is sized by whichever runs out first — viewport height or
   the content column — and the chrome above and below follows it, so the
   whole block always lands inside a single locked screen. */
.n8n {
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  border: 1px solid var(--fn-rule);
  background: color-mix(in srgb, var(--color-bg) 88%, transparent);
  box-shadow: 0 32px 90px rgba(0, 0, 0, 0.5);
}
.n8n__bar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--fn-rule);
  background: color-mix(in srgb, var(--color-surface) 70%, transparent);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
}
.n8n__file { color: var(--color-text-muted); }
.n8n__pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border: 1px solid color-mix(in srgb, var(--fn-ok) 45%, transparent);
  color: var(--fn-ok);
  border-radius: 999px;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.n8n__pill i { width: 5px; height: 5px; border-radius: 50%; background: var(--fn-ok); }
.n8n__exec { margin-left: auto; }
.n8n__exec b { color: var(--color-text-muted); font-weight: var(--fw-medium); }

.n8n__canvas {
  position: relative;
  container-type: inline-size;
  aspect-ratio: 1000 / 520;
  width: auto;
  /* Whatever is left after the scene's own chrome. The 4vh term matters:
     the heading, caption and padding above and below all use clamps, so
     the space they take grows with the viewport and a fixed allowance
     overflows on a large screen. */
  height: min(
    clamp(230px, calc(100svh - 470px - 5vh), 620px),
    calc((min(var(--fn-max), 100vw) - 2 * var(--fn-gutter)) * 0.52)
  );
  --nb: 8cqw;                    /* node box = 80 viewBox units */
  background-color: color-mix(in srgb, var(--color-bg) 92%, transparent);
  background-image: radial-gradient(circle, color-mix(in srgb, var(--color-text) 13%, transparent) 1px, transparent 1px);
  background-size: 22px 22px;
  background-position: -1px -1px;
}

.n8n__wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.n8n__base path {
  fill: none;
  stroke: color-mix(in srgb, var(--color-text) 22%, transparent);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
}
.n8n__flow path {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2.4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 0.14 0.86;
  stroke-dashoffset: 1;
  opacity: 0;
}
.n8n__flow path.is-run { opacity: 1; }
.n8n__flow path.is-done {
  opacity: 1;
  stroke: color-mix(in srgb, var(--fn-ok) 78%, transparent);
  stroke-width: 1.8;
  stroke-dasharray: none;
  stroke-dashoffset: 0;
}

.n8n__node {
  position: absolute;
  left: calc(var(--x) * 1%);
  top: calc(var(--y) * 1%);
  width: 0; height: 0;
}
.n8n__box {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: var(--nb); height: var(--nb);
  display: grid;
  place-items: center;
  border: 1.5px solid color-mix(in srgb, var(--color-text) 26%, transparent);
  border-radius: calc(var(--nb) * 0.16);
  background: var(--color-surface);
  color: var(--color-text-dim);
  transition: border-color 300ms var(--ease-out), color 300ms var(--ease-out),
              box-shadow 300ms var(--ease-out), transform 300ms var(--ease-out),
              background-color 300ms var(--ease-out);
}
.n8n__box svg { width: 42%; height: 42%; }
.n8n__node--trigger .n8n__box {
  border-radius: calc(var(--nb) * 0.5) calc(var(--nb) * 0.16) calc(var(--nb) * 0.16) calc(var(--nb) * 0.5);
}

.n8n__io {
  position: absolute;
  top: 50%;
  width: calc(var(--nb) * 0.1);
  height: calc(var(--nb) * 0.1);
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-text) 34%, transparent);
  transform: translateY(-50%);
}
.n8n__io--in  { left: calc(var(--nb) * -0.05); }
.n8n__io--out { right: calc(var(--nb) * -0.05); }
.n8n__io--o1 { top: 22%; }
.n8n__io--o2 { top: 50%; }
.n8n__io--o3 { top: 78%; }

.n8n__label {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, calc(var(--nb) * 0.5 + 6px));
  display: grid;
  justify-items: center;
  gap: 1px;
  line-height: 1.12;
  white-space: nowrap;
  text-align: center;
}
/* When the canvas gets short the branch rows close up. The node name has
   to survive; its type does not, so that is what goes rather than letting
   the two collide or shrinking the name below the legibility floor. */
@container (max-width: 520px) {
  .n8n__label small { display: none; }
}
.n8n__label strong {
  color: var(--color-text-muted);
  font-size: max(12px, 1.4cqw);
  font-weight: var(--fw-medium);
  letter-spacing: -0.01em;
  transition: color 300ms var(--ease-out);
}
.n8n__label small {
  color: var(--color-text-fade);
  font-family: var(--font-mono);
  font-size: max(11px, 1.15cqw);
}

/* node states */
.n8n__node.is-done .n8n__box {
  border-color: color-mix(in srgb, var(--fn-ok) 60%, transparent);
  color: var(--fn-ok);
  background: color-mix(in srgb, var(--fn-ok) 9%, var(--color-surface));
}
.n8n__node.is-done .n8n__label strong { color: var(--color-text); }
.n8n__node.is-run .n8n__box {
  border-color: var(--color-accent);
  color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 16%, transparent),
              0 12px 40px color-mix(in srgb, var(--color-accent) 24%, transparent);
  transform: translate(-50%, -50%) scale(1.06);
}
.n8n__node.is-run .n8n__label strong { color: var(--color-accent); }
.n8n__node.is-skip .n8n__box { opacity: 0.34; }
.n8n__node.is-skip .n8n__label { opacity: 0.34; }

.n8n__log {
  display: grid;
  gap: 2px;
  min-height: 4.6em;
  padding: 10px 14px;
  border-top: 1px solid var(--fn-rule);
  background: color-mix(in srgb, var(--color-bg) 60%, transparent);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
}
.n8n__log i { font-style: normal; animation: fn-in 320ms var(--ease-out) both; }
.n8n__log i.ok { color: var(--fn-ok); }
.n8n__log i.hold { color: var(--color-accent); }

@keyframes fn-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* =========================================================
   CONSOLE (shared by commerce / enrollment / recovery)
   ========================================================= */
.fn-console {
  border: 1px solid var(--fn-rule);
  background: var(--fn-panel);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 32px 90px rgba(0, 0, 0, 0.5);
}
.fn-console__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--fn-rule);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
}
.fn-console__bar > b { margin-left: auto; color: var(--color-text-muted); font-weight: var(--fw-medium); }
.fn-console__dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--fn-ok);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--fn-ok) 18%, transparent);
}

.fn-surfaces {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--fn-rule-soft);
}
.fn-surfaces--2 { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
.fn-srf { background: color-mix(in srgb, var(--color-bg) 66%, transparent); padding: 14px; }
.fn-srf > header {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--fn-rule-soft);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-dim);
}
.fn-srf > header b { color: var(--color-text-muted); font-weight: var(--fw-medium); }

.fn-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  font-size: 0.86rem;
}
.fn-row span { color: var(--color-text-dim); font-family: var(--font-mono); font-size: 0.72rem; }
.fn-row b { font-weight: var(--fw-regular); text-align: right; }
.fn-row.is-hot b { color: var(--color-accent); }

.fn-gate {
  margin-top: 12px;
  padding: 10px;
  border: 1px dashed color-mix(in srgb, var(--color-text) 20%, transparent);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
  transition: border-color 300ms var(--ease-out), background-color 300ms var(--ease-out);
}
.fn-gate b {
  padding: 3px 8px;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.fn-gate.is-held { border-color: color-mix(in srgb, var(--color-accent) 55%, transparent); }
.fn-gate.is-held b { color: var(--color-accent); }
.fn-gate.is-ok { border-style: solid; border-color: color-mix(in srgb, var(--fn-ok) 50%, transparent); }
.fn-gate.is-ok b { color: var(--fn-ok); }

.fn-product { display: grid; justify-items: start; gap: 6px; }
.fn-product picture { display: block; width: 100%; }
.fn-product img {
  width: 100%;
  height: clamp(76px, 15vh, 150px);
  object-fit: cover;
  border: 1px solid var(--fn-rule-soft);
}
.fn-product strong { font-weight: var(--fw-medium); font-size: 0.9rem; }
.fn-product__price { font-family: var(--font-mono); font-size: 0.95rem; color: var(--color-text); }
.fn-product__price.is-new { color: var(--color-accent); }

.fn-rec {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 10px;
  margin-bottom: 6px;
  border: 1px solid var(--fn-rule-soft);
  font-size: 0.82rem;
  transition: border-color 300ms var(--ease-out), background-color 300ms var(--ease-out);
}
.fn-rec span { color: var(--color-text-dim); font-family: var(--font-mono); font-size: 0.7rem; }
.fn-rec b { font-family: var(--font-mono); font-weight: var(--fw-regular); }
.fn-rec.is-stale b { color: var(--color-text-fade); text-decoration: line-through; }
.fn-rec.is-sync {
  border-color: color-mix(in srgb, var(--fn-ok) 45%, transparent);
  background: color-mix(in srgb, var(--fn-ok) 7%, transparent);
}
.fn-rec.is-sync b { color: var(--fn-ok); }

.fn-stream {
  display: grid;
  gap: 2px;
  min-height: 4.2em;
  padding: 10px 14px;
  border-top: 1px solid var(--fn-rule);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
}
.fn-stream i { font-style: normal; animation: fn-in 320ms var(--ease-out) both; }
.fn-stream i.ok { color: var(--fn-ok); }
.fn-stream i.hold { color: var(--color-accent); }

.fn-pipe {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 12px 14px;
  border-bottom: 1px solid var(--fn-rule-soft);
}
.fn-pipe span {
  flex: 1;
  position: relative;
  padding: 7px 6px;
  border: 1px solid var(--fn-rule-soft);
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-fade);
  transition: color 300ms var(--ease-out), border-color 300ms var(--ease-out), background-color 300ms var(--ease-out);
}
.fn-pipe span + span { margin-left: 8px; }
.fn-pipe span.is-done { color: var(--fn-ok); border-color: color-mix(in srgb, var(--fn-ok) 40%, transparent); }
.fn-pipe span.is-live {
  color: var(--color-accent);
  border-color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
}

.fn-caps { display: flex; gap: 6px; margin-bottom: 10px; }
.fn-caps span {
  flex: 1;
  padding: 8px 4px;
  border: 1px solid var(--fn-rule-soft);
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
  transition: all 300ms var(--ease-out);
}
.fn-caps span.is-held {
  border-color: var(--color-accent);
  color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 12%, transparent);
}
.fn-caps span.is-gone { opacity: 0.3; text-decoration: line-through; }

/* --- recovery scan --- */
.fn-scan { display: grid; }
.fn-scan__row {
  display: grid;
  grid-template-columns: 4.6rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  /* Six rows plus the meter is the tallest console on the page, so the
     row rhythm has to give way on a short screen rather than overflow. */
  padding: clamp(6px, 1.2vh, 13px) 14px;
  border-bottom: 1px solid var(--fn-rule-soft);
  font-size: 0.86rem;
  transition: background-color 320ms var(--ease-out);
}
.fn-scan__row > span { font-family: var(--font-mono); font-size: 0.78rem; color: var(--color-text-muted); }
.fn-scan__row > em { font-style: normal; color: var(--color-text-dim); font-size: 0.82rem; }
.fn-scan__row > small {
  padding: 4px 10px;
  border: 1px solid var(--fn-rule);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-fade);
  white-space: nowrap;
}
.fn-scan__row.is-scanning { background: color-mix(in srgb, var(--color-text) 5%, transparent); }
.fn-scan__row.is-scanning > small { color: var(--color-text-muted); }
.fn-scan__row.is-gap { background: color-mix(in srgb, var(--color-accent) 7%, transparent); }
.fn-scan__row.is-gap > small { border-color: color-mix(in srgb, var(--color-accent) 55%, transparent); color: var(--color-accent); }
.fn-scan__row.is-ok > small { border-color: color-mix(in srgb, var(--fn-ok) 45%, transparent); color: var(--fn-ok); }

.fn-meter {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px;
  padding: clamp(11px, 1.9vh, 17px) 14px;
}
.fn-meter strong {
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.6vw, 3rem);
  font-weight: var(--fw-light);
  line-height: 1;
}
.fn-meter > span { color: var(--color-text-muted); font-size: 0.9rem; }
.fn-meter b { color: var(--color-text); font-weight: var(--fw-medium); }
.fn-stamp {
  margin-left: auto;
  padding: 5px 11px;
  border: 1px solid color-mix(in srgb, var(--fn-ok) 45%, transparent);
  color: var(--fn-ok);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* =========================================================
   VOICE RECEPTION
   ========================================================= */
.fn-call {
  display: grid;
  grid-template-columns: minmax(0, 0.62fr) minmax(0, 1.25fr) minmax(0, 0.6fr);
  gap: 1px;
  border: 1px solid var(--fn-rule);
  background: var(--fn-rule-soft);
  box-shadow: 0 32px 90px rgba(0, 0, 0, 0.5);
}
.fn-phone, .fn-transcript, .fn-vmeta { background: color-mix(in srgb, var(--color-bg) 82%, transparent); }

.fn-phone { padding: 16px; display: grid; align-content: start; gap: 16px; }
.fn-phone__top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
}
.fn-phone__live { display: inline-flex; align-items: center; gap: 6px; color: var(--fn-ok); }
.fn-phone__live i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--fn-ok);
  animation: fn-pulse 1.8s ease-in-out infinite;
}
@keyframes fn-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.25; } }
.fn-phone__top b { color: var(--color-text); font-family: var(--font-mono); font-weight: var(--fw-medium); }

.fn-phone__who { display: grid; justify-items: center; gap: 6px; text-align: center; padding: 10px 0; }
.fn-phone__avatar {
  width: 58px; height: 58px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--fn-rule);
  background: color-mix(in srgb, var(--color-mark) 30%, transparent);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--color-text);
}
.fn-phone__who strong { font-weight: var(--fw-medium); font-size: 0.98rem; }
.fn-phone__who small { color: var(--color-text-dim); font-size: 0.76rem; }

.fn-wave {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  height: 46px;
}
/* Scaled rather than resized: 28 bars re-laying out every scroll frame is
   exactly the thrash this effect cannot afford. */
.fn-wave i {
  display: block;
  width: 3px;
  height: 40px;
  background: color-mix(in srgb, var(--color-accent) 70%, transparent);
  transform: scaleY(var(--h, 0.15));
  transition: transform 120ms linear;
}
.fn-phone__foot { display: flex; justify-content: center; gap: 14px; }
.fn-phone__foot span {
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid var(--fn-rule);
  background: color-mix(in srgb, var(--color-surface) 70%, transparent);
}
.fn-phone__foot span.is-end { background: color-mix(in srgb, #B4332F 70%, transparent); border-color: transparent; }

.fn-transcript { display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; }
.fn-transcript__bar {
  display: flex;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--fn-rule-soft);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--color-text-dim);
}
.fn-transcript__body {
  padding: 14px;
  display: grid;
  gap: 10px;
  align-content: start;
  max-height: min(46vh, 340px);
  overflow: hidden;
}
.fn-tline { display: grid; gap: 3px; animation: fn-in 340ms var(--ease-out) both; }
.fn-tline span {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-fade);
}
.fn-tline p { margin: 0; font-size: 0.92rem; line-height: 1.5; color: var(--color-text-muted); }
.fn-tline--agent p { color: var(--color-text); }
.fn-tline--agent span { color: var(--color-accent); }

.fn-vmeta { padding: 14px; display: grid; align-content: start; gap: 14px; }
.fn-vmeta__block { display: grid; gap: 5px; padding-bottom: 12px; border-bottom: 1px solid var(--fn-rule-soft); }
.fn-vmeta__block:last-child { border-bottom: 0; padding-bottom: 0; }
.fn-vmeta span {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-fade);
}
.fn-vmeta strong { font-weight: var(--fw-medium); font-size: 0.94rem; line-height: 1.35; }

/* =========================================================
   COCKPIT
   ========================================================= */
.fn-cockpit {
  border: 1px solid var(--fn-rule);
  background: var(--fn-panel);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 32px 90px rgba(0, 0, 0, 0.5);
}
.fn-kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--fn-rule-soft);
  border-bottom: 1px solid var(--fn-rule-soft);
}
.fn-kpi { background: color-mix(in srgb, var(--color-bg) 66%, transparent); padding: 14px; display: grid; gap: 6px; }
.fn-kpi > span {
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.fn-kpi strong {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 3vw, 2.6rem);
  font-weight: var(--fw-light);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.fn-kpi i { font-style: normal; font-family: var(--font-mono); font-size: 0.7rem; color: var(--color-text-fade); }
.fn-kpi i.up { color: var(--fn-ok); }
.fn-kpi i.down { color: var(--color-accent); }
.fn-kpi--money strong { color: var(--color-accent); }

.fn-cockpit__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: 1px; background: var(--fn-rule-soft); }
.fn-chart, .fn-queue { background: color-mix(in srgb, var(--color-bg) 66%, transparent); }
.fn-chart__bar {
  display: flex;
  justify-content: space-between;
  padding: 11px 14px;
  border-bottom: 1px solid var(--fn-rule-soft);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-text-dim);
}
.fn-chart__bar b { color: var(--color-text); font-weight: var(--fw-medium); }

.fn-bars { padding: 14px; display: grid; gap: 12px; }
.fn-bar { display: grid; grid-template-columns: 5.4rem minmax(0, 1fr) 2.6rem; align-items: center; gap: 10px; }
.fn-bar span { color: var(--color-text-muted); font-size: 0.82rem; }
.fn-bar i {
  height: 8px;
  background: linear-gradient(90deg, var(--color-mark), color-mix(in srgb, var(--color-mark) 55%, var(--color-text)));
  transform: scaleX(calc(var(--v) * var(--grow, 0)));
  transform-origin: left center;
  transition: transform 200ms linear;
}
.fn-bar b { font-family: var(--font-mono); font-size: 0.78rem; text-align: right; color: var(--color-text); }

.fn-queue__rows { padding: 8px 0; }
.fn-qrow {
  display: grid;
  grid-template-columns: 3.6rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 380ms var(--ease-out), transform 380ms var(--ease-out);
}
.fn-qrow + .fn-qrow { border-top: 1px solid var(--fn-rule-soft); }
.fn-qrow.is-in { opacity: 1; transform: none; }
.fn-body:not(.pf-js) .fn-qrow { opacity: 1; transform: none; }
.fn-qrow em { font-style: normal; font-size: 0.86rem; color: var(--color-text-muted); }
.fn-qrow > b { font-family: var(--font-mono); font-size: 0.8rem; color: var(--color-text); }
.fn-pri {
  padding: 3px 7px;
  border: 1px solid var(--fn-rule);
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-text-dim);
}
.fn-pri--hi { border-color: color-mix(in srgb, var(--color-accent) 55%, transparent); color: var(--color-accent); }

/* =========================================================
   CLOSE
   ========================================================= */
.fn-close { border-top: 1px solid var(--fn-rule); }
.fn-close__inner { display: grid; justify-items: start; }
.fn-close__cta { margin-top: clamp(30px, 5vh, 52px); }
.fn-close__note {
  margin: clamp(20px, 3vh, 30px) 0 0;
  max-width: 46ch;
  color: var(--color-text-muted);
  font-size: 0.95rem;
}
.fn-close__note a { color: var(--color-text); border-bottom: 1px solid var(--color-accent); text-decoration: none; }
.fn-close__note a:hover { color: var(--color-accent); }

/* =========================================================
   LIVE SECTION — tap targets
   The speed-to-lead block is the one place on the page a visitor
   actually has to hit something, so its controls get a real target
   rather than the 18px box the browser gives a bare checkbox.
   ========================================================= */
.fn-body .pf-consent {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
}
/* showcase.css sizes these for a denser layout; the funnel holds every
   label at or above the 11px floor the rest of the page uses. */
.fn-body .pf-field label,
.fn-body .pf-stl__clock span,
.fn-body .pf-stl__steps li,
.fn-body .pf-stl__alts-title,
.fn-body .pf-live-note,
.fn-body .pf-foot__inner span { font-size: 0.72rem; }
.fn-body .pf-live-note { line-height: 1.5; }
.fn-body .pf-scrollhint span { font-size: 0.72rem; }
.fn-body .pf-consent input[type="checkbox"],
.fn-body .pf-alt__consent input[type="checkbox"] {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  accent-color: var(--color-accent);
  cursor: pointer;
}
.fn-body .pf-alt__consent {
  display: grid;
  place-items: center;
  min-width: 44px;
  min-height: 44px;
  cursor: pointer;
}

/* =========================================================
   PROGRESS RAIL — the only navigation on the page
   ========================================================= */
.fn-rail {
  position: fixed;
  right: clamp(12px, 1.6vw, 22px);
  top: 50%;
  z-index: 55;
  transform: translateY(-50%);
  display: grid;
  gap: 2px;
}
.fn-rail a {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 9px;
  padding: 7px 4px;
  min-height: 32px;
  text-decoration: none;
  color: var(--color-text-fade);
}
.fn-rail a i {
  width: 34px; height: 2px;
  background: currentColor;
  transform: scaleX(0.65);
  transform-origin: right center;
  transition: transform 300ms var(--ease-out), background-color 300ms var(--ease-out);
}
/* Absolutely positioned so the label costs no width. Left in the flow it made
   the rail 125px wide and pushed it straight into the content column. */
.fn-rail a span {
  position: absolute;
  right: calc(100% + 9px);
  top: 50%;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(-50%) translateX(6px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
}
.fn-rail:hover a span,
.fn-rail a:focus-visible span { opacity: 1; transform: translateY(-50%) translateX(0); }
.fn-rail a:hover { color: var(--color-text-muted); }
.fn-rail a.is-live { color: var(--color-accent); }
.fn-rail a.is-live i { transform: scaleX(1); }
.fn-rail a.is-past { color: var(--color-text-dim); }

/* =========================================================
   VISUAL PASS — type, depth, ambient colour, accent discipline
   Layout, scroll mechanics and markup are untouched; this block
   only restyles surfaces.
   ========================================================= */

/* ---------------------------------------------------------
   1 · TYPOGRAPHY
   Space Grotesk ships no true italic, so the old Cormorant-italic
   emphasis would render as a synthesised oblique. Emphasis moves to
   weight and brightness instead.
   --------------------------------------------------------- */
.fn-hero__title,
.fx__title,
.fn-wwd__name,
.pf-live-title,
.pf-statement {
  font-family: var(--font-display);
  font-weight: 300;
  letter-spacing: -0.012em;
  color: color-mix(in srgb, var(--color-text) 88%, transparent);
}
/* Cormorant has a true italic, so emphasis goes back to it — and the accent
   goes with it, the way the home page hero does. This is the one decorative
   use of the accent on the page; every other instance marks live state. */
.fn-hero__title em,
.fx__title em,
.fn-wwd__name em,
.pf-live-title em {
  font-style: italic;
  font-weight: 400;
  color: var(--color-accent);
}
.fn-hero__title { font-weight: 300; letter-spacing: -0.018em; line-height: 1.06; }

/* Cormorant runs small for its point size; the display steps go up a notch
   so the titles keep the presence they had at the sans sizes. */
.fn-hero__title { font-size: clamp(2.9rem, 7vw, 6rem); }
.fx__title      { font-size: clamp(2.1rem, 4vw, 3.7rem); }
.fn-wwd__name   { font-size: clamp(2.3rem, 4vw, 3.9rem); }
.pf-statement   { font-weight: 300; letter-spacing: -0.01em; }

/* The split-reveal wraps every word in an `overflow: hidden` mask sized to
   the line box. Cormorant's small x-height fitted a 1.04 line-height; Space
   Grotesk's glyph box is ~1.25em and got sliced top and bottom. `clip` plus
   a clip margin extends the painted area without moving anything, so
   ascenders and descenders survive and the slide-up reveal still hides the
   word beforehand (it starts a full 105% below). */
.fn-hero__title .pf-w {
  overflow: clip;
  overflow-clip-margin: 0.22em;
}

/* Unread words in a scroll-lit statement were at 1.7:1 — invisible rather
   than dim. Lifted until the not-yet-read text is still readable; the jump
   to full Paper still carries the effect. */
/* `:not(.is-lit)` is load-bearing. Without it this rule outranks
   showcase.css's `.pf-statement .pf-word.is-lit` — equal specificity, later
   file — and the scroll-lighting silently stops. The statement just sits
   there dim, which is exactly how it was behaving. */
.fn-body .pf-statement .pf-word:not(.is-lit) {
  color: color-mix(in srgb, var(--color-text) 38%, transparent);
}
.fn-body .pf-statement .pf-word.is-lit { color: var(--color-text); }

/* Display numerals read better with the tabular, lining set. */
.fn-meter strong,
.fn-kpi strong,
.fn-spec strong {
  font-family: var(--font-display);
  font-weight: 400;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.005em;
}

/* Micro-labels: JetBrains Mono, tracked slightly tighter than Geist Mono
   needed, and no longer brass. */
.fn-kicker {
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-weight: 500;
  letter-spacing: 0.18em;
}
.fn-kicker .pf-dot { background: currentColor; }

/* ---------------------------------------------------------
   2 · GEOMETRY & DEPTH
   Outer panels round and clip; inner grid cells stay square so the
   1px seams between surfaces survive, and the parent's radius does
   the cutting.
   --------------------------------------------------------- */
.fn-console,
.fn-cockpit,
.n8n,
.fn-call,
.fn-det,
.fn-body .pf-stl__main,
.fn-body .pf-stl__alts {
  border-radius: var(--fn-radius);
  border: var(--fn-border);
  box-shadow: var(--fn-shadow);
  overflow: hidden;
}
.fn-console,
.fn-cockpit,
.n8n,
.fn-call { box-shadow: var(--fn-shadow-lg); }
.fn-det.is-live { box-shadow: var(--fn-shadow); }

/* Second tier: standalone boxes that sit inside a panel. */
.fn-mini { border-radius: var(--fn-radius-sm); overflow: hidden; }
.fn-rec,
.fn-gate,
.fn-caps span,
.fn-pipe span,
.fn-scan__row > small,
.fn-stamp,
.fn-pri,
.fn-body .pf-field input,
.fn-body .pf-alt { border-radius: var(--fn-radius-xs); }

.fn-body .pf-field input {
  border: var(--fn-border);
  background: rgba(255, 255, 255, 0.03);
}
.fn-body .pf-field input:focus-visible {
  border-color: color-mix(in srgb, var(--color-live) 60%, transparent);
  background: rgba(255, 255, 255, 0.05);
}

/* The n8n node keeps a squarer face — it is meant to read as a canvas
   node, not a card — but loses the hard corner. */
.n8n__box { border-radius: calc(var(--nb) * 0.22); }
.n8n__node--trigger .n8n__box {
  border-radius: calc(var(--nb) * 0.5) calc(var(--nb) * 0.22) calc(var(--nb) * 0.22) calc(var(--nb) * 0.5);
}

/* ---------------------------------------------------------
   3 · AMBIENT COLOUR
   A fixed light field behind everything, so scrolling moves content
   through the light instead of dragging the gradient with it. Fixed
   positioning rather than background-attachment: fixed, which repaints
   the whole layer on every frame and is broken on iOS.
   --------------------------------------------------------- */
.fn-body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(90% 55% at 50% -12%, rgba(45, 212, 191, 0.10), transparent 55%),
    radial-gradient(70% 50% at 6% 12%,   rgba(28, 63, 138, 0.34),  transparent 62%),
    radial-gradient(65% 55% at 96% 84%,  rgba(255, 182, 39, 0.05), transparent 60%);
}

/* Sections carry a faint top edge of the same teal so the light reads as
   continuous rather than only living behind the hero. */
.fx::after,
.fn-wwd::after {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(45, 212, 191, 0.22), transparent);
}

/* ---------------------------------------------------------
   4 · ACCENT DISCIPLINE
   Amber is state, never decoration: running nodes, live pills, the
   things a queue is waiting on, and the primary CTA. Green stays
   "already done", so the two are never confusable.
   Amber over green as the accent is deliberate — green already means
   completed on the canvas and in the scan.
   --------------------------------------------------------- */
.n8n__node.is-run .n8n__box {
  box-shadow: 0 0 0 4px rgba(255, 182, 39, 0.16),
              0 12px 40px rgba(255, 182, 39, 0.28);
}
.n8n__pill {
  color: var(--color-live);
  border-color: color-mix(in srgb, var(--color-live) 45%, transparent);
  background: rgba(255, 182, 39, 0.08);
}
.n8n__pill i { background: var(--color-live); }
.fn-phone__live { color: var(--color-live); }
.fn-phone__live i { background: var(--color-live); }
.fn-console__dot {
  background: var(--color-live);
  box-shadow: 0 0 0 4px rgba(255, 182, 39, 0.18);
}

/* Decoration that used to be brass, returned to Paper. */
.fn-close__note a,
.pf-live-note a {
  border-bottom-color: rgba(255, 255, 255, 0.28);
}

/* ---------------------------------------------------------
   5 · BUTTONS
   --------------------------------------------------------- */
.fn-body .btn {
  gap: 7px;
  padding: 9px 17px;
  border-radius: 99px;
  font-family: var(--font-sans);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  text-transform: none;
  transition: transform 220ms var(--ease-out),
              background-color 220ms var(--ease-out),
              border-color 220ms var(--ease-out),
              box-shadow 220ms var(--ease-out),
              color 220ms var(--ease-out);
}
.fn-body .btn svg { width: 13px; height: 13px; }

.fn-body .btn--primary {
  background: var(--color-live);
  color: var(--color-live-ink);
  border-color: transparent;
  box-shadow: 0 6px 20px -6px rgba(255, 182, 39, 0.5);
}
.fn-body .btn--primary:hover {
  background: #FFC44D;
  transform: translateY(-1px);
  box-shadow: 0 14px 30px -8px rgba(255, 182, 39, 0.55);
}
.fn-body .btn--primary:active { transform: translateY(0); }

.fn-body .btn--ghost {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--color-text-muted);
  border-color: rgba(255, 255, 255, 0.14);
  box-shadow: none;
}
.fn-body .btn--ghost:hover {
  color: var(--color-text);
  border-color: rgba(255, 255, 255, 0.28);
  background: rgba(255, 255, 255, 0.04);
  transform: none;
}

/* The hero CTA was sized like a banner. It is a button. */
.fn-hero__cta { padding: 12px 22px; font-size: 0.88rem; }

/* The header CTA is deliberately not the accent. Amber in the nav, the hero
   and the close would make three competing primaries and cost the accent its
   meaning — and `.nav__cta` in styles.css overrides the primary background
   while leaving its dark ink behind, which is unreadable. */
.fn-body .nav__cta,
.fn-body .nav__cta.btn--primary {
  padding: 9px 17px;
  font-size: 0.8rem;
  background: transparent;
  color: var(--color-text-muted);
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: none;
}
.fn-body .nav__cta:hover,
.fn-body .nav__cta.btn--primary:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.3);
  color: var(--color-text);
  transform: none;
}

/* =========================================================
   TRY IT — channel chooser + usage budget
   ========================================================= */
/* This section carries the only form on the page, so it is the densest one.
   Everything below is sized so it still lands inside a single screen. */
.fn-body .pf-live-section { padding-block: clamp(56px, 7.5vh, 104px); }
.fn-body .pf-live-head { margin-bottom: clamp(18px, 2.4vh, 30px); }
.fn-body .pf-live-title {
  margin: 0;
  font-size: clamp(1.8rem, 3vw, 2.9rem);
  line-height: 1.08;
}
.fn-body .pf-live-lead { margin: 12px 0 0; max-width: 54ch; }

.fn-try {
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(0, 0.85fr);
  gap: clamp(14px, 1.6vw, 22px);
  align-items: start;
}
.fn-try__main,
.fn-try__alts {
  padding: clamp(18px, 2.2vw, 26px);
  border-radius: var(--fn-radius);
  border: var(--fn-border);
  background: color-mix(in srgb, var(--color-surface) 60%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: var(--fn-shadow);
}

.fn-try__ch { margin: 0 0 14px; padding: 0; border: 0; display: grid; gap: 6px; }
.fn-try__ch legend {
  padding: 0 0 8px;
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.fn-try__opt {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: 44px;
  padding: 9px 13px;
  border-radius: var(--fn-radius-sm);
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.02);
  cursor: pointer;
  transition: border-color 200ms var(--ease-out), background-color 200ms var(--ease-out);
}
.fn-try__opt:hover { border-color: rgba(255, 255, 255, 0.18); }
.fn-try__opt input {
  flex: 0 0 auto;
  width: 18px; height: 18px;
  margin-top: 2px;
  accent-color: var(--color-live);
  cursor: pointer;
}
.fn-try__optbody { display: grid; gap: 2px; }
.fn-try__optbody b { color: var(--color-text); font-size: 0.9rem; font-weight: 600; }
.fn-try__optbody small { color: var(--color-text-dim); font-size: 0.78rem; line-height: 1.45; }
.fn-try__opt:has(input:checked) {
  border-color: color-mix(in srgb, var(--color-live) 55%, transparent);
  background: rgba(255, 182, 39, 0.07);
}
.fn-try__opt:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.fn-try__fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.fn-try__fields .pf-field.is-optional { opacity: 0.55; }
.fn-try__fields .pf-field.is-optional label::after {
  content: " · not needed for text";
  color: var(--color-text-fade);
  font-family: var(--font-mono);
  font-size: 0.9em;
}

.fn-try__go { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 14px; }
.fn-try__clock { display: grid; gap: 2px; }
.fn-try__clock strong {
  font-family: var(--font-mono);
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}
.fn-try__clock span { color: var(--color-text-dim); font-size: 0.74rem; }

.fn-try__steps {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.fn-try__steps li {
  padding: 5px 11px;
  border-radius: 99px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--color-text-fade);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  transition: color 260ms var(--ease-out), border-color 260ms var(--ease-out), background-color 260ms var(--ease-out);
}
.fn-try__steps li.is-done {
  color: var(--color-live);
  border-color: color-mix(in srgb, var(--color-live) 45%, transparent);
  background: rgba(255, 182, 39, 0.08);
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}
/* The elapsed time is the point of the trace, so it is set apart rather than
   run into the label. */
/* Same size as the label. Shrinking it would drop the type under 11px, which
   is the floor this page is held to; the tone carries the distinction. */
.fn-try__steps li em {
  font-style: normal;
  font-variant-numeric: tabular-nums;
  font-size: 1em;
  color: color-mix(in srgb, var(--color-live) 68%, var(--color-text));
  opacity: 0.72;
}
/* A step that ran and did not land. The lead still went through, so this is
   a note, not an alarm. */
.fn-try__steps li.is-warn {
  color: var(--color-text-muted);
  border-color: rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.03);
}
.fn-try__steps li.is-warn em { color: var(--color-text-muted); }

/* When the phone network refuses a country, the browser call is the answer and
   it is already on screen. This points at it once rather than making the
   visitor re-read the paragraph to find out where to go. */
.fn-body .pf-alt.is-nudge {
  border-color: color-mix(in srgb, var(--color-live) 55%, transparent);
  background: rgba(255, 182, 39, 0.07);
  animation: fn-nudge 2.4s var(--ease-out) 1;
}
@keyframes fn-nudge {
  0%   { box-shadow: 0 0 0 0 rgba(255, 182, 39, 0.42); }
  70%  { box-shadow: 0 0 0 12px rgba(255, 182, 39, 0); }
  100% { box-shadow: 0 0 0 0 rgba(255, 182, 39, 0); }
}
@media (prefers-reduced-motion: reduce) {
  /* The colour change alone still carries it. */
  .fn-body .pf-alt.is-nudge { animation: none; }
}

/* The budget. Dots first, because a count of remaining runs is read faster
   as objects than as a sentence. */
.fn-try__quota {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  padding: 9px 12px;
  border-radius: var(--fn-radius-xs);
  border: 1px dashed rgba(255, 255, 255, 0.12);
  color: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: 0.72rem;
}
.fn-try__dots { display: inline-flex; gap: 5px; }
.fn-try__dots i {
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.22);
}
.fn-try__dots i.is-left { background: var(--color-live); border-color: transparent; }
.fn-try__main.is-spent .fn-try__quota {
  border-style: solid;
  border-color: color-mix(in srgb, var(--color-live) 35%, transparent);
  color: var(--color-text);
}

.fn-try__altstitle {
  margin: 0 0 12px;
  color: var(--color-text-dim);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

@media (max-width: 900px) {
  .fn-try { grid-template-columns: minmax(0, 1fr); }
}

/* =========================================================
   PICK YOUR PROBLEM — scroll-driven carousel
   ========================================================= */
.fn-pick__rail {
  position: relative;
  overflow: hidden;
  /* Half a gutter of bleed, not a full one — a full gutter reaches under the
     fixed progress rail. The edge mask does the rest of the work. */
  margin-inline: calc(var(--fn-gutter) * -0.5);
  padding-block: 8px;
  /* Feathered edges, so cards leave the frame instead of being guillotined. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.fn-pick__track {
  display: flex;
  gap: clamp(14px, 1.6vw, 22px);
  width: max-content;
  will-change: transform;
}

.fn-pick__card {
  position: relative;
  flex: 0 0 auto;
  width: clamp(258px, 26vw, 340px);
  display: grid;
  align-content: start;
  gap: 10px;
  padding: clamp(18px, 2vw, 24px);
  border-radius: var(--fn-radius);
  border: var(--fn-border);
  background: color-mix(in srgb, var(--color-surface) 52%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  text-decoration: none;
  overflow: hidden;
  opacity: 0.34;
  transform: scale(0.94);
  filter: blur(1px);
  transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out),
              filter 420ms var(--ease-out), border-color 420ms var(--ease-out),
              background-color 420ms var(--ease-out), box-shadow 420ms var(--ease-out);
}
.fn-pick__card.is-live {
  opacity: 1;
  transform: none;
  filter: none;
  border-color: rgba(255, 255, 255, 0.2);
  background: color-mix(in srgb, var(--color-surface) 78%, transparent);
  box-shadow: var(--fn-shadow);
}
.fn-pick__card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(70% 60% at 50% 0%, rgba(255, 182, 39, 0.12), transparent 70%);
  opacity: 0;
  transition: opacity 420ms var(--ease-out);
}
.fn-pick__card.is-live::after { opacity: 1; }
.fn-pick__card.is-live:hover { transform: translateY(-3px); }
.fn-body:not(.pf-js) .fn-pick__card { opacity: 1; transform: none; filter: none; }

.fn-pick__tag {
  color: var(--color-live);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.fn-pick__card strong {
  color: var(--color-text);
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 1.5vw, 1.5rem);
  font-weight: 300;
  font-style: italic;
  line-height: 1.24;
  letter-spacing: -0.005em;
  text-wrap: balance;
}
.fn-pick__meta { color: var(--color-text-dim); font-family: var(--font-mono); font-size: 0.7rem; }
.fn-pick__go {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 4px;
  color: var(--color-text);
  font-size: 0.82rem;
  font-weight: 600;
}
.fn-pick__go i { font-style: normal; transition: transform 260ms var(--ease-out); }
.fn-pick__card:hover .fn-pick__go i { transform: translateX(4px); }

.fn-pick__dots { display: flex; justify-content: center; gap: 8px; margin-top: 6px; }
.fn-pick__dots button {
  width: 26px; height: 26px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.fn-pick__dots button::before {
  content: "";
  width: 22px; height: 2px;
  background: rgba(255, 255, 255, 0.18);
  transition: background-color 300ms var(--ease-out), transform 300ms var(--ease-out);
}
.fn-pick__dots button.is-live::before { background: var(--color-live); transform: scaleY(2); }

@media (prefers-reduced-motion: reduce) {
  .fn-pick__card, .fn-pick__go i, .fn-pick__dots button::before { transition-duration: 1ms !important; }
  .fn-pick__card { filter: none !important; }
}

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 1180px) {
  .fn-call { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
  .fn-vmeta { grid-column: 1 / -1; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .fn-vmeta__block { border-bottom: 0; padding-bottom: 0; }
}

@media (max-width: 1000px) {
  .fn-rail { display: none; }

  /* Stacked, the two columns must share one containing block or the
     header cannot stick over the detail it belongs to. */
  .fn-wwd__grid { display: block; }
  .fn-wwd__stick { position: static; min-height: auto; padding-block: 20px 18px; }
  .fn-wwd__stick::after {
    content: "";
    position: absolute;
    inset: auto 0 0;
    height: 34px;
    pointer-events: none;
    background: linear-gradient(to bottom, var(--color-bg), transparent);
    transform: translateY(100%);
  }
  .fn-wwd__left {
    position: sticky;
    top: 0;
    z-index: 2;
    background: color-mix(in srgb, var(--color-bg) 94%, transparent);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
  }
  .fn-wwd__slide:not(.is-live) { display: none; }
  .fn-wwd__name { font-size: clamp(1.7rem, 7vw, 2.4rem); }
  .fn-wwd__name br { display: none; }
  .fn-wwd__facts { display: none; }
  .fn-wwd__right { padding-block: 26px 60px; }

  /* Once the surfaces stack they have to pay for the height they now cost,
     or the console outgrows the locked screen. This starts here rather than
     at the phone breakpoint because this is where the stacking starts. */
  .fn-surfaces { grid-template-columns: minmax(0, 1fr); }
  .fn-surfaces--2 { grid-template-columns: minmax(0, 1fr); }
  .fn-cockpit__grid { grid-template-columns: minmax(0, 1fr); }
  .fn-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fn-product picture { display: none; }
  .fn-srf { padding: 12px; }
  .fn-qrow { padding: 7px 12px; }
  .fn-bars { padding: 12px; gap: 9px; }
}

@media (max-width: 760px) {
  .fn-body { --fx-pace: 66; }

  /* Every scene still has to land inside one phone screen, so the chrome
     around each console gets tightened rather than the console clipped. */
  .fx__inner { padding-block: 76px 28px; gap: 12px; }
  .fx__title { font-size: clamp(1.5rem, 6.4vw, 2rem); }
  .fx__title br { display: none; }
  .fx__cap { font-size: 0.9rem; min-height: 3.2em; margin-top: 10px; }

  .fn-srf { padding: 9px; }
  .fn-srf > header { margin-bottom: 7px; padding-bottom: 6px; }
  .fn-row { padding: 4px 0; }
  .fn-gate { margin-top: 8px; padding: 7px; }
  .fn-rec { padding: 6px 9px; margin-bottom: 4px; }
  .fn-stream, .n8n__log { min-height: 3em; padding: 8px 12px; }
  .fn-pipe { padding: 10px 12px; }

  .fn-call { grid-template-columns: minmax(0, 1fr); }
  /* Label and value on one line each — stacked, this block was costing
     a third of the console's height for three short strings. */
  .fn-vmeta { grid-template-columns: minmax(0, 1fr); gap: 0; padding: 4px 12px; }
  .fn-vmeta__block {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--fn-rule-soft);
  }
  .fn-vmeta__block:last-child { border-bottom: 0; }
  .fn-vmeta strong { text-align: right; font-size: 0.86rem; }
  .fn-transcript__body { max-height: 28vh; padding: 10px 12px; }
  .fn-phone { padding: 12px; gap: 10px; }
  .fn-phone__who { display: none; }
  .fn-wave { height: 34px; }

  .fn-meter { padding: 12px; gap: 8px; }
  .fn-meter strong { font-size: 1.9rem; }
  .fn-stamp { margin-left: 0; }
  .fn-scan__row { padding: 9px 12px; gap: 8px; }
  .fn-scan__row > em { display: none; }

  .fn-kpi { padding: 10px; gap: 4px; }
  .fn-kpi strong { font-size: 1.5rem; }
  .fn-bars { padding: 10px; gap: 9px; }
  .fn-bar { grid-template-columns: 4.6rem minmax(0, 1fr) 2.4rem; }
  .fn-qrow { padding: 8px 12px; }
  .fn-chart__bar { padding: 9px 12px; }

  .fn-clockrow { grid-template-columns: 6rem minmax(0, 1fr) 2.8rem; }
  .fn-spec { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fn-spec > div:nth-child(3) { border-left: 0; }
  .fn-spec > div:nth-child(n+3) { border-top: 1px solid var(--fn-rule-soft); }

  /* Legibility floor. Mono labels that read fine at 0.7rem on a desktop
     panel are unreadable at arm's length on a phone. */
  .fn-mini__bar, .fn-mini__rows span, .fn-spec span, .fn-audit li span,
  .fn-det__tag, .fn-srf > header, .fn-row span, .fn-gate, .fn-gate b,
  .fn-rec span, .fn-stream, .n8n__log, .fn-console__bar, .fn-pipe span,
  .fn-caps span, .fn-scan__row > small, .fn-stamp, .fn-kpi > span,
  .fn-chart__bar, .fn-pri, .fn-vmeta span, .fn-tline span,
  .fn-transcript__bar, .fn-phone__top, .n8n__bar, .n8n__pill,
  .fn-close__note, .pf-live-note {
    font-size: 0.7rem;
  }
  .fn-kicker { font-size: 0.7rem; }
  /* Same floor for the pieces that come from showcase.css. */
  .fn-kpi i,
  .pf-field label,
  .pf-stl__clock span,
  .pf-stl__steps li,
  .pf-stl__alts-title,
  .pf-foot__inner span { font-size: 0.72rem; }

  /* Last of the height budget: the cockpit is the densest console and
     the commerce one carries a fourth surface. */
  /* A 38px pill is fine under a mouse and too small under a thumb. */
  .fn-body .btn { min-height: 44px; padding: 12px 18px; }

  .fx__inner { padding-block: 68px 14px; }
  .fn-console__bar { padding: 8px 12px; }
  .fn-qrow { padding: 5px 12px; }
  .fn-stream, .n8n__log { min-height: 2.6em; }
  /* Plus Jakarta Sans sets a taller line box than Geist did, so the phone
     rhythm gives back the few pixels the new type costs. */
  .fn-kpi { padding: 7px 10px; gap: 2px; }
  .fn-kpi strong { font-size: 1.2rem; }
  .fn-bars { gap: 5px; }
  .fn-bar i { height: 5px; }
  .fn-queue__rows { padding: 2px 0; }
  .fn-chart__bar { padding: 6px 12px; }
  .fn-srf { padding: 8px; }
  .fn-console__bar { padding: 7px 12px; }
  .fn-qrow { padding: 4px 12px; }
  .fn-bars { gap: 7px; }
  .fn-bar i { height: 6px; }
  .fn-qrow { padding: 6px 12px; }
  .fn-chart__bar { padding: 8px 12px; }
}

/* --- n8n canvas on phones: stack it rather than shrink the type
       below the legibility floor. Wires and the grid go away; the
       execution order is carried by the vertical order instead. --- */
@media (max-width: 760px) {
  .n8n__canvas {
    aspect-ratio: auto;
    container-type: normal;
    --nb: 40px;
    display: grid;
    gap: 6px;
    padding: 12px;
    background-image: none;
  }
  .n8n__wires { display: none; }
  .n8n__node {
    position: static;
    width: auto; height: auto;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 10px;
    border: 1px solid var(--fn-rule-soft);
  }
  .n8n__box { position: static; transform: none; flex: 0 0 auto; }
  .n8n__node.is-run .n8n__box { transform: none; }
  .n8n__io { display: none; }
  .n8n__label { position: static; transform: none; justify-items: start; text-align: left; }
  .n8n__label strong { font-size: 0.9rem; }
  .n8n__label small { font-size: 0.7rem; }
  .n8n__node.is-run { border-color: color-mix(in srgb, var(--color-accent) 50%, transparent); }
  .n8n__node.is-done { border-color: color-mix(in srgb, var(--fn-ok) 40%, transparent); }
}

/* ---------------------------------------------------------
   SHORT VIEWPORTS
   A pinned scene has to fit one screen or it gets clipped. On a
   short phone these consoles simply do not, so the pin is released
   and the scene flows normally — funnel.js switches to reading the
   section's own travel across the viewport, so every panel still
   builds itself as you scroll. Nothing is hidden and no type shrinks.
   --------------------------------------------------------- */
@media (max-height: 700px) and (max-width: 900px) {
  .fx__track { min-height: 0; }
  .fx__pin {
    position: static;
    height: auto;
    overflow: visible;
    padding-block: 10vh;
  }
  .fx__inner { padding-block: 0; }
}

/* =========================================================
   REDUCED MOTION
   State still changes with scroll — it just stops sliding.
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  .fn-det, .fn-wwd__slide, .fn-qrow, .n8n__box, .n8n__label strong,
  .fn-bar i, .fn-wave i, .fx__cap, .fn-rec, .fn-gate, .fn-pipe span, .fn-caps span {
    transition-duration: 1ms !important;
  }
  .fn-det, .fn-wwd__slide { filter: none !important; }
  .fn-stream i, .n8n__log i, .fn-tline { animation: none !important; }
  .fn-phone__live i { animation: none !important; }
}
