/*
 * THE APP SKIN — our layer over Espen's vendored marketing site.
 *
 * Loaded after his tokens.css and site.css on every page (the `site:sync` script injects the
 * link), so it re-points his `--x-*` tokens at the logged-in app's own values and adds the
 * app's material: Figtree and JetBrains Mono, daylight blue-white surfaces, blue-tinted
 * hairlines and shadows, the app's easing. It lives in this repo, not in his, so a re-sync
 * keeps it. Values are quoted from `src/app/simple.css` (`--smp-*`).
 *
 * Two rules from Espen's side hold here too: NO BLACK (text stays his navy ink, shadows are
 * navy-teal, never rgb(0 0 0)). Brand ramp: Color Palette v2 (design/tokens/palettes/v2.json).
 *
 * Motion is progressive and finite: nothing loops, everything has a resting state, and
 * `prefers-reduced-motion: reduce` gets the resting state with no animation at all.
 */

/* ---------- 0. Color Palette v2 — overrides Espen's generated tokens.css ---------- */
:root {
  --x-base-highlight: #55b4fa;
  --x-base-ui: #2071c5;
  --x-base-ink: #034da8;
  --x-base-tint: #e6f4fe;
  --x-base-dark: #55b4fa;
  --x-coral: #ffd166;
  --x-coral-deep: #8a6a00;
  --x-warn: #8a6a00;
  --x-success: #217a45;
  --x-fig-attract: #2071c5;
  --x-fig-convert: #034da8;
  --x-fig-warn: #8a6a00;
  --x-fig-attract-inverse: #55b4fa;
  --x-fig-convert-inverse: #55b4fa;
}

/* ---------- 1. the app's faces (self-hosted, SIL OFL — licences beside the files) ---------- */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("../fonts/figtree-latin-var.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("../fonts/figtree-latin-ext-var.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-latin-var.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-latin-ext-var.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* The width of a scrolling diagram's "there is more" fade — registered so it can animate. */
@property --sk-fade {
  syntax: "<length>";
  inherits: false;
  initial-value: 40px;
}

/* ---------- 2. tokens: Espen's names, the app's values ---------- */
:root {
  --x-font-sans: "Figtree", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --x-font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --x-surface-100: #f7fbfd; /* --smp-bg: daylight, the app's canvas */
  --x-line: #d3e7f2; /* --smp-border */
  --x-line-strong: #b7d6e8; /* --smp-border-strong — decorative hairlines only */
  --x-radius-sm: 4px; /* --smp-r-sm */
  --x-radius-md: 8px; /* --smp-r-md */
  --x-radius-lg: 12px; /* --smp-r-lg */
  --x-radius-xl: 18px;

  --sk-panel-2: #eff7fb; /* --smp-panel-2 */
  --sk-ink-deep: #00577d; /* the dark end of the headline accent: 7.3:1 on white */
  --sk-accent-end: #0086c0; /* its light end: 4.06:1 on white, 3.6:1 on the hero bloom */
  --sk-field-edge: #6b8ba3; /* a form field's edge: 3.59:1 on white, 3.45:1 on #f7fbfd (1.4.11) */
  --sk-sh-card: 0 1px 2px rgb(16 48 58 / 5%), 0 1px 3px rgb(16 48 58 / 8%); /* --smp-sh-card */
  --sk-sh-pop: 0 4px 16px rgb(16 48 58 / 14%); /* --smp-sh-pop */
  --sk-sh-lift: 0 22px 44px -22px rgb(16 48 58 / 32%), 0 2px 6px rgb(16 48 58 / 6%);
  --sk-ease: cubic-bezier(0.32, 0.72, 0, 1); /* --smp-ease */
  --sk-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --sk-ease-in-out: cubic-bezier(0.45, 0, 0.2, 1);
  --sk-ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1);
  --sk-t-feedback: 120ms; /* --smp-t-feedback */
  --sk-t-state: 200ms; /* --smp-t-state */
  --sk-track-engrave: 0.14em; /* --smp-track-engrave */
  --sk-masthead-h: 64px;

  color-scheme: light;
  interpolate-size: allow-keywords;
}

/* ---------- 3. base ---------- */
html {
  scroll-padding-top: calc(var(--sk-masthead-h) + 16px);
}
body {
  line-height: 1.6;
  overflow-x: clip; /* not hidden: hidden would make body a scroller and unstick the masthead */
  text-rendering: optimizeLegibility;
}
::selection {
  background: #cdeefe;
  color: var(--x-ink);
}
p,
li,
.lede,
.card-body,
.step-body {
  text-wrap: pretty;
}
.lede {
  font-size: clamp(17px, 1.35vw, 19px);
  line-height: 1.6;
}
/* No border-radius here: an outline already follows the element's own corners, and setting
   one would reshape every focused button and card to it. */
:focus-visible {
  outline: 3px solid var(--x-base-ui);
  outline-offset: 3px;
}

/* ---------- 4. type: weight is the hierarchy (the app's rule) ---------- */
h1,
h2,
h3,
h4 {
  font-weight: 700;
  letter-spacing: -0.022em;
}
h1 {
  font-weight: 760;
  letter-spacing: -0.034em;
}
h2 {
  font-size: clamp(28px, 3.5vw, 44px);
  letter-spacing: -0.03em;
  line-height: 1.08;
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--x-font-sans);
  font-size: var(--x-size-micro);
  font-weight: 650;
  letter-spacing: var(--sk-track-engrave);
}
.eyebrow::before {
  content: "";
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--x-base-highlight), var(--x-base-ui));
}
.band-ink .eyebrow::before {
  background: var(--x-base-dark);
}

/* ---------- 5. masthead: frosted, sticky, on the content grid, with a reading line ---------- */
.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in oklab, var(--x-surface-000) 86%, transparent);
  border-bottom: 1px solid color-mix(in oklab, var(--x-line) 85%, transparent);
  backdrop-filter: saturate(170%) blur(16px);
  -webkit-backdrop-filter: saturate(170%) blur(16px);
}
@supports not (backdrop-filter: blur(1px)) {
  .masthead {
    background: var(--x-surface-000);
  }
}
/* The same width and gutter as .wrap, so the logo lines up with every heading below it and
   Sign up ends where the content ends. */
.nav {
  max-width: 1080px;
  min-height: var(--sk-masthead-h);
  padding-block: 10px;
  padding-inline: 24px;
}
.brand {
  gap: 0;
}
.brand-mark {
  display: block;
  height: 28px;
  width: auto;
  transition: transform var(--sk-t-state) var(--sk-ease);
}
.colophon .brand-mark {
  height: 32px;
}
.brand:hover .brand-mark {
  transform: scale(1.03);
}

/* Language menu — a chrome control, not a peer of the section links */
.lang-menu {
  position: relative;
  margin-right: var(--x-space-2);
}
.lang-menu > summary {
  list-style: none;
}
.lang-menu > summary::-webkit-details-marker {
  display: none;
}
.lang-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 11px 0 12px;
  border: 1px solid var(--x-line-strong);
  border-radius: 999px;
  background: var(--x-surface-000);
  color: var(--x-ink);
  font-family: var(--x-font-mono);
  font-size: var(--x-size-caption);
  font-weight: 650;
  letter-spacing: 0.08em;
  cursor: pointer;
  box-shadow: 0 1px 0 rgb(16 48 58 / 4%);
  transition:
    border-color var(--sk-t-feedback) var(--sk-ease),
    box-shadow var(--sk-t-state) var(--sk-ease),
    background-color var(--sk-t-feedback) var(--sk-ease);
}
.lang-trigger:hover,
.lang-menu[open] .lang-trigger {
  border-color: color-mix(in oklab, var(--x-base-ui) 55%, var(--x-line-strong));
  box-shadow: 0 8px 18px -14px rgb(16 48 58 / 35%);
}
.lang-caret {
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.7;
  transition: transform var(--sk-t-state) var(--sk-ease);
}
.lang-menu[open] .lang-caret {
  transform: rotate(180deg);
}
.lang-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 40;
  min-width: 10.5rem;
  padding: 6px;
  border: 1px solid var(--x-line);
  border-radius: 14px;
  background: var(--x-surface-000);
  box-shadow: var(--sk-sh-lift);
}
.lang-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  color: var(--x-ink);
  text-decoration: none;
  font-size: var(--x-size-sm);
  font-weight: 550;
  letter-spacing: -0.01em;
  transition: background-color var(--sk-t-feedback) var(--sk-ease);
}
.lang-option:hover {
  background: color-mix(in oklab, var(--x-base-ui) 10%, transparent);
}
.lang-option.is-current {
  font-weight: 700;
  background: color-mix(in oklab, var(--x-base-ui) 12%, transparent);
}
.lang-option.is-current::after {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--x-base-ui);
}
.nav-link {
  position: relative;
  font-weight: 550;
  transition: color var(--sk-t-feedback) var(--sk-ease);
}
.nav-links .nav-link::after {
  content: "";
  position: absolute;
  inset: auto 0 -7px;
  height: 2px;
  border-radius: 2px;
  background: var(--x-base-ui);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--sk-t-state) var(--sk-ease);
}
.nav-links .nav-link:hover::after,
.nav-links .nav-link[aria-current="page"]::after {
  transform: scaleX(1);
}
.nav-login {
  font-weight: 650;
}
.burger-panel {
  border-color: var(--x-line);
  box-shadow: var(--sk-sh-lift);
}
/* The 390px masthead: brand, Log in, Sign up and the menu on one line. Language moves into the
   menu (it lists both languages), and the Sign up label no longer breaks in two. */
@media (max-width: 479px) {
  .nav,
  .nav-actions {
    gap: 10px;
  }
  .lang,
  .lang-menu {
    display: none;
  }
}

/* ---------- 6. calls to action ---------- */
.cta {
  white-space: nowrap;
  font-weight: 650;
  letter-spacing: -0.005em;
  transition:
    background-color var(--sk-t-feedback) var(--sk-ease),
    color var(--sk-t-feedback) var(--sk-ease),
    border-color var(--sk-t-feedback) var(--sk-ease),
    box-shadow var(--sk-t-state) var(--sk-ease),
    transform var(--sk-t-state) var(--sk-ease);
}
.cta-primary {
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 30%),
    0 10px 24px -12px color-mix(in oklab, var(--x-coral) 75%, transparent);
}
.cta-primary:hover {
  transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 20%),
    0 16px 30px -14px color-mix(in oklab, var(--x-coral-deep) 80%, transparent);
}
.cta:active {
  transform: translateY(0) scale(0.98);
}
.masthead .cta-sm {
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 30%),
    0 6px 14px -8px color-mix(in oklab, var(--x-coral) 70%, transparent);
}
.hero2 .cta-primary {
  padding: 14px 24px;
  font-size: 17px;
}
.hero2 .cta-primary::after {
  content: "→" / "";
  transition: transform var(--sk-t-state) var(--sk-ease);
}
.hero2 .cta-primary:hover::after {
  transform: translateX(3px);
}

/* ---------- 7. bands ---------- */
.band {
  padding-block: clamp(64px, 8.5vw, 116px);
}
.band-sunken {
  border-block: 1px solid color-mix(in oklab, var(--x-line) 55%, transparent);
}
/* The navy band keeps Espen's flat, validated navy under its text. The texture is a 5%-white
   dot field — too faint to move any text pair — and a hairline of the brand ramp on top. */
.band-ink {
  position: relative;
  isolation: isolate;
}
.band-ink::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: radial-gradient(
    circle at 1px 1px,
    rgb(255 255 255 / 5%) 1px,
    transparent 1.5px
  );
  background-size: 24px 24px;
  pointer-events: none;
}
.band-ink::after {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 2px;
  background: linear-gradient(
    90deg,
    transparent,
    var(--x-base-dark) 30%,
    var(--x-base-highlight) 70%,
    transparent
  );
  opacity: 0.7;
}

/* ---------- 8. the first band: daylight, an instrument grid, a bloom ---------- */
main > .band:first-child {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(48px, 7vw, 104px) clamp(64px, 8vw, 120px);
  background:
    radial-gradient(55% 60% at 8% 0%, #e6f7ff 0%, transparent 70%),
    radial-gradient(45% 55% at 100% 35%, #eef9ff 0%, transparent 70%),
    linear-gradient(180deg, var(--x-surface-000) 0%, var(--x-surface-100) 100%);
}
/* The grid sits behind the orb: beside the copy on a wide screen, under it on a narrow one —
   never behind the words. */
main > .band:first-child::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: radial-gradient(
    circle at 1px 1px,
    color-mix(in oklab, var(--x-base-ui) 28%, transparent) 1px,
    transparent 1.5px
  );
  background-size: 22px 22px;
  mask-image: radial-gradient(60% 70% at 78% 42%, #fff 10%, transparent 78%);
  -webkit-mask-image: radial-gradient(60% 70% at 78% 42%, #fff 10%, transparent 78%);
  pointer-events: none;
}
@media (max-width: 1023px) {
  main > .band:first-child::before {
    mask-image: radial-gradient(75% 30% at 50% 84%, #fff 10%, transparent 75%);
    -webkit-mask-image: radial-gradient(75% 30% at 50% 84%, #fff 10%, transparent 75%);
  }
}

/* ---------- 9. the hero ---------- */
.hero2 {
  align-items: center;
}
/* Two columns only from 1024px: below that the orb would shrink beside a tall heading, so it
   moves under the copy instead. */
@media (min-width: 900px) and (max-width: 1023px) {
  .hero2 {
    grid-template-columns: 1fr;
  }
}
@media (min-width: 1024px) {
  .hero2 {
    grid-template-columns: 1.2fr 0.8fr;
    gap: clamp(32px, 4vw, 56px);
  }
}
.hero2 h1 {
  font-size: clamp(38px, 4.9vw, 58px);
  line-height: 1.04;
  max-width: 17ch;
  margin-bottom: var(--x-space-6);
}
.hero2 h1 em {
  background: linear-gradient(
    100deg,
    var(--sk-ink-deep) 0%,
    var(--x-base-ink) 45%,
    var(--sk-accent-end) 100%
  );
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@media (forced-colors: active) {
  .hero2 h1 em {
    background: none;
    color: CanvasText;
  }
}
.hero2 .lede {
  font-size: clamp(17px, 1.45vw, 20px);
  max-width: 48ch;
}
.kicker {
  font-family: var(--x-font-mono);
  font-size: var(--x-size-micro);
  letter-spacing: 0.05em;
  color: var(--x-ink-secondary);
  background: color-mix(in oklab, var(--x-surface-000) 72%, transparent);
  border-color: var(--x-line);
  border-radius: 10px;
  padding: 6px 12px;
  box-shadow: var(--sk-sh-card);
  max-width: 100%;
}
/* Narrow: fill each line, then break after a separator — site:sync binds every " ·" to the
   word before it, so no line can start with one. Wide: one line; from 1024px the copy column
   grows to hold it (an fr track honours its content's min-content) and the orb's gives way. */
@media (max-width: 1023px) {
  .kicker {
    letter-spacing: 0.02em;
  }
}
@media (min-width: 1024px) {
  .kicker {
    white-space: nowrap;
  }
}

/* ---------- 10. the Growth Cycle orb (replaces the video placeholder) ---------- */
.orb {
  position: relative;
  isolation: isolate;
  margin: 0;
  justify-self: center;
  width: min(86vw, 420px);
  aspect-ratio: 1;
}
/* Beside the copy it may be larger than its column and bleed toward the page edge: the first
   band clips it, so it can never cause a sideways scroll. */
@media (min-width: 1024px) {
  .orb {
    justify-self: end;
    width: clamp(380px, 38vw, 560px);
    margin-inline-end: clamp(-120px, -5vw, -24px);
  }
}
.orb::before {
  content: "";
  position: absolute;
  inset: 14%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    color-mix(in oklab, var(--x-base-highlight) 26%, transparent),
    transparent 70%
  );
  filter: blur(28px);
}
.orb svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.orb-stop-a {
  stop-color: var(--x-base-highlight);
}
.orb-stop-b {
  stop-color: var(--x-base-ui);
}
.orb-stop-c {
  stop-color: var(--x-base-ink);
}
.orb-core-a {
  stop-color: var(--x-base-tint);
}
.orb-core-b {
  stop-color: var(--x-base-tint);
  stop-opacity: 0.55;
}
.orb-core-c {
  stop-color: var(--x-base-tint);
  stop-opacity: 0;
}
/* Every turn so far, compounding outward into workstream 1. */
.orb-spiral {
  fill: none;
  stroke: color-mix(in oklab, var(--x-base-ui) 45%, transparent);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
}
/* This turn. */
.orb-ring {
  fill: none;
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 0;
}
.orb-comet {
  fill: none;
  stroke: var(--x-base-highlight);
  stroke-width: 8;
  stroke-linecap: round;
  stroke-dasharray: 4 96;
  stroke-dashoffset: -96;
  opacity: 0;
}
.orb-return {
  fill: none;
  stroke: var(--x-base-ink);
  stroke-width: 1.75;
  stroke-dasharray: 5 5;
}
.orb-arrow-head {
  fill: var(--x-base-ink);
}
.orb-node {
  transform-box: fill-box;
  transform-origin: center;
}
.orb-node circle {
  fill: var(--x-surface-000);
  stroke: var(--x-base-ui);
  stroke-width: 2.5;
}
.orb-node text {
  font-family: var(--x-font-mono);
  font-size: 15px;
  font-weight: 700;
  fill: var(--x-base-ink);
  text-anchor: middle;
  dominant-baseline: central;
}
.orb-mark {
  filter: drop-shadow(0 6px 14px rgb(16 48 58 / 18%));
}

/* ---------- 11. surfaces: the app's panels, hairlines and shadows ---------- */
.card,
.door,
.ws,
.ladder,
.moves,
.honest,
.login-card {
  box-shadow: var(--sk-sh-card);
}
.fig-panel {
  border-radius: var(--x-radius-xl);
  box-shadow: var(--sk-sh-card);
}
.fig-panel::before {
  height: 3px;
  background: linear-gradient(
    90deg,
    var(--x-base-highlight),
    var(--x-base-ui) 55%,
    var(--x-base-ink)
  );
}
.band-ink .fig-panel::before {
  background: linear-gradient(90deg, var(--x-base-dark), var(--x-base-highlight));
}
.band-ink .card,
.band-ink .fig-panel {
  box-shadow: none;
}
/* Phones: the diagrams keep Espen's 520px floor (narrower, their labels would fall under the
   site's 12.5px minimum), so they scroll sideways — and that has to be visible. The panel runs
   edge to edge, a fade on its right edge says "more this way", and the fade lifts as you reach
   the end (an animation driven by the panel's own inline scroll). The workstream rings scale to
   fit (site.css gives them min-width 0), so they keep their card. */
@media (max-width: 567px) {
  .fig-panel {
    margin-inline: -24px;
    border-inline: 0;
    border-radius: 0;
    scrollbar-width: thin;
    scrollbar-color: var(--x-line-strong) transparent;
    mask-image: linear-gradient(90deg, #fff calc(100% - var(--sk-fade)), transparent);
    -webkit-mask-image: linear-gradient(90deg, #fff calc(100% - var(--sk-fade)), transparent);
  }
  .fig-panel::before {
    border-radius: 0;
  }
  .ws-cycle .fig-panel {
    margin-inline: 0;
    border-inline: 1px solid var(--x-fig-edge);
    border-radius: var(--x-radius-xl);
    mask-image: none;
    -webkit-mask-image: none;
  }
  .ws-cycle .fig-panel::before {
    border-radius: var(--x-radius-xl) var(--x-radius-xl) 0 0;
  }
  @supports (animation-timeline: scroll()) {
    .fig-panel {
      animation: sk-unfade linear both;
      animation-timeline: scroll(self inline);
    }
  }
}
/* A workstream's input → output line wraps, rather than scrolling inside itself and cutting a
   word in half. */
.chain {
  white-space: normal;
  overflow-x: visible;
  text-wrap: pretty;
}
a.card,
.pm-plate {
  transition:
    transform var(--sk-t-state) var(--sk-ease),
    box-shadow var(--sk-t-state) var(--sk-ease),
    border-color var(--sk-t-state) var(--sk-ease);
}
a.card:hover,
.pm-plate:hover {
  transform: translateY(-3px);
  box-shadow: var(--sk-sh-lift);
  border-color: var(--x-line-strong);
}
.card-feature {
  box-shadow:
    inset 0 0 0 1px var(--x-base-ui),
    0 18px 40px -24px color-mix(in oklab, var(--x-base-ui) 55%, transparent);
}
.card-n,
.step-n,
.ws-n {
  font-variant-numeric: tabular-nums;
}
.ltable-fig {
  border-radius: var(--x-radius-lg);
}
.ltable thead th {
  font-family: var(--x-font-sans);
  letter-spacing: var(--sk-track-engrave);
}

/* ---------- 12. disclosures: the eight workstreams and the answers ---------- */
.ws,
.faq > summary {
  transition:
    border-color var(--sk-t-state) var(--sk-ease),
    box-shadow var(--sk-t-state) var(--sk-ease),
    color var(--sk-t-feedback) var(--sk-ease);
}
.ws:hover {
  border-color: var(--x-line-strong);
}
.ws[open] {
  box-shadow: var(--sk-sh-pop);
}
.faq > summary:hover {
  color: var(--x-base-ink);
}
@supports selector(::details-content) {
  @media (prefers-reduced-motion: no-preference) {
    .faq::details-content,
    .ws::details-content {
      block-size: 0;
      overflow: clip;
      transition:
        block-size 360ms var(--sk-ease),
        content-visibility 360ms allow-discrete;
    }
    .faq[open]::details-content,
    .ws[open]::details-content {
      block-size: auto;
    }
  }
}

/* ---------- 13. the form: a field you can see, the app's focus halo ---------- */
.lead input {
  border-color: var(--sk-field-edge);
  transition:
    border-color var(--sk-t-feedback) var(--sk-ease),
    box-shadow var(--sk-t-state) var(--sk-ease);
}
.lead input:focus {
  outline: none;
  border-color: var(--x-base-ui);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--x-base-ui) 22%, transparent);
}

/* ---------- 14. colophon ---------- */
.colophon {
  background: linear-gradient(180deg, var(--x-surface-100), var(--sk-panel-2));
}
.foot-head {
  font-family: var(--x-font-sans);
  font-weight: 650;
  letter-spacing: var(--sk-track-engrave);
}
.foot-link {
  transition: color var(--sk-t-feedback) var(--sk-ease);
}

/* ════════════════════════════════════════════════════════════════════════════
   MOTION — progressive, finite, and absent under prefers-reduced-motion.
   ════════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: no-preference) {
  /* Between pages: the masthead stays put and the page settles in (no client JS). */
  @view-transition {
    navigation: auto;
  }
  .masthead {
    view-transition-name: masthead;
  }
  ::view-transition-old(root) {
    animation: sk-page-out 160ms var(--sk-ease) both;
  }
  ::view-transition-new(root) {
    animation: sk-page-in 380ms var(--sk-ease-out) both;
  }

  /* The hero arrives: the words rise out of a soft focus, in reading order. The heading is
     never faded — it is the largest paint on the page and must count as painted at once. */
  .hero2 > div:first-child > * {
    animation: sk-rise 780ms var(--sk-ease-out) both;
  }
  .hero2 > div:first-child > h1 {
    animation-name: sk-focus;
    animation-delay: 40ms;
  }
  .hero2 > div:first-child > :nth-child(3) {
    animation-delay: 160ms;
  }
  .hero2 > div:first-child > :nth-child(4) {
    animation-delay: 240ms;
  }
  .hero2 > div:first-child > :nth-child(5) {
    animation-delay: 320ms;
  }

  /* The orb, once: the spiral of every turn so far winds out from the centre and arrives at
     workstream 1; this turn's ring then draws from there, a spark riding its tip, each
     workstream landing as the tip reaches it; the dashed return leg closes the loop. Rest. */
  .orb-core,
  .orb-mark {
    animation: sk-fade 900ms var(--sk-ease-out) both;
  }
  .orb-spiral {
    animation: sk-draw 1.1s var(--sk-ease-in-out) 150ms both;
  }
  .orb-ring {
    animation: sk-draw 1.8s linear 1.2s both;
  }
  .orb-comet {
    animation: sk-comet 1.8s linear 1.2s both;
  }
  .orb-node {
    animation: sk-pop 560ms var(--sk-ease-pop) both;
    animation-delay: calc(1.2s + var(--i, 0) * 225ms);
  }
  .orb-return {
    animation: sk-fade 520ms var(--sk-ease-out) 2.95s both;
  }

  /* On a narrow screen the orb sits below the fold, where a timed sequence would finish before
     anyone scrolled to it — so there the reader's scroll draws it, over the stretch where the
     orb comes into view. Scroll-driven, so nothing moves on its own. */
  @media (max-width: 1023px) {
    @supports (animation-timeline: view()) {
      .orb {
        view-timeline: --orb block;
      }
      .orb-core,
      .orb-mark,
      .orb-spiral,
      .orb-ring,
      .orb-comet,
      .orb-node,
      .orb-return {
        animation-duration: auto;
        animation-delay: 0s;
        animation-timeline: --orb;
      }
      .orb-core,
      .orb-mark {
        animation-range: cover 4% cover 20%;
      }
      .orb-spiral {
        animation-range: cover 8% cover 26%;
      }
      .orb-ring,
      .orb-comet {
        animation-range: cover 24% cover 44%;
      }
      .orb-node {
        animation-range: cover calc(24% + var(--i, 0) * 2.5%) cover calc(28% + var(--i, 0) * 2.5%);
      }
      .orb-return {
        animation-range: cover 43% cover 48%;
      }
    }
  }

  /* Down the page: headings, diagrams and cards rise into place as they enter, driven by the
     scroll. The range is capped in pixels so a tall block is never left half-faded on screen. */
  @supports (animation-timeline: view()) {
    .band-head,
    .fig,
    .band .cards > *,
    .band .doors > * {
      animation: sk-reveal linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 160px;
    }
  }

  /* The reading line under the masthead: how far down this page you are. */
  @supports (animation-timeline: scroll()) {
    .masthead::after {
      content: "";
      position: absolute;
      inset: auto 0 -1px;
      height: 2px;
      transform-origin: left;
      background: linear-gradient(90deg, var(--x-base-highlight), var(--x-base-ui));
      animation: sk-progress linear both;
      animation-timeline: scroll(root);
    }
  }
}

@keyframes sk-page-out {
  to {
    opacity: 0;
    translate: 0 -6px;
  }
}
@keyframes sk-page-in {
  from {
    opacity: 0;
    translate: 0 10px;
  }
}
@keyframes sk-rise {
  from {
    opacity: 0;
    translate: 0 16px;
    filter: blur(6px);
  }
}
@keyframes sk-focus {
  from {
    translate: 0 12px;
    filter: blur(10px);
  }
}
@keyframes sk-fade {
  from {
    opacity: 0;
  }
}
@keyframes sk-draw {
  from {
    stroke-dashoffset: 100;
  }
}
/* Invisible until the ring starts, so the spark never waits at the top while the spiral draws. */
@keyframes sk-comet {
  0% {
    stroke-dashoffset: 4;
    opacity: 0;
  }
  3%,
  90% {
    opacity: 1;
  }
  100% {
    stroke-dashoffset: -96;
    opacity: 0;
  }
}
@keyframes sk-pop {
  from {
    opacity: 0;
    scale: 0.4;
  }
}
@keyframes sk-reveal {
  from {
    opacity: 0;
    translate: 0 28px;
  }
}
@keyframes sk-progress {
  from {
    scale: 0 1;
  }
  to {
    scale: 1 1;
  }
}
@keyframes sk-unfade {
  85% {
    --sk-fade: 40px;
  }
  100% {
    --sk-fade: 0px;
  }
}
