/* ── Systemsoft — "Editorial ink" ────────────────────────────────────────
   Calm, spacious company site. Warm-neutral paper ground, deep teal accent,
   serif display headings on a humanist-sans body. Light-first, with a fully
   designed dark theme. Theme-aware via tokens: :root defines light, the
   prefers-color-scheme media query provides the OS-dark default, and the
   [data-theme] attribute (set by the header toggle) wins in both directions.

   Built to be the proof of its own pitch: WCAG 2.1 AA contrast, visible focus
   states, semantic landmarks, fully readable without JavaScript. js/app.js is
   pure enhancement. */

/* ── tokens ─────────────────────────────────────────────────────────── */
:root {
  --bg: #f4f4f1;
  --bg-soft: #ecece6;
  --bg-card: #fbfbf9;
  --ink: #1b1e24;
  --dim: #545860;
  --faint: #61645c;
  --line: #dad9d2;
  --acc: #0d5a52;
  --acc-ink: #ffffff;
  --acc-link: #0a4f48;
  --acc-soft: rgba(13, 90, 82, 0.08);
  --ok: #0d7a54;
  --ok-ink: #0a5a3e;
  --err: #b5361f;

  --font-serif: "Iowan Old Style", "Palatino Linotype", Palatino, Charter, Georgia, "Times New Roman", serif;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --maxw: 1120px;
  --rad: 8px;
  --rad-lg: 14px;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --header-h: 68px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #16171a; --bg-soft: #1c1e21; --bg-card: #1e2023;
    --ink: #eceae4; --dim: #a2a49c; --faint: #8f9289; --line: #2a2c2c;
    --acc: #58c8b7; --acc-ink: #0a1614; --acc-link: #74d4c3; --acc-soft: rgba(88, 200, 183, 0.12);
    --ok: #58c8a0; --ok-ink: #58c8a0; --err: #ff9a86;
  }
}
:root[data-theme="light"] {
  --bg: #f4f4f1; --bg-soft: #ecece6; --bg-card: #fbfbf9;
  --ink: #1b1e24; --dim: #545860; --faint: #61645c; --line: #dad9d2;
  --acc: #0d5a52; --acc-ink: #ffffff; --acc-link: #0a4f48; --acc-soft: rgba(13, 90, 82, 0.08);
  --ok: #0d7a54; --ok-ink: #0a5a3e; --err: #b5361f;
}
:root[data-theme="dark"] {
  --bg: #16171a; --bg-soft: #1c1e21; --bg-card: #1e2023;
  --ink: #eceae4; --dim: #a2a49c; --faint: #8f9289; --line: #2a2c2c;
  --acc: #58c8b7; --acc-ink: #0a1614; --acc-link: #74d4c3; --acc-soft: rgba(88, 200, 183, 0.12);
  --ok: #58c8a0; --ok-ink: #58c8a0; --err: #ff9a86;
}

/* ── display preferences (the on-site accessibility panel) ──────────────
   These are the dogfooding proof: text size, extra contrast and reduce-motion
   are user-controllable on the same pages (set by js/app.js on <html>), not a
   separate stripped-down site. */
/* Text size scales the root font-size, so every rem-based size grows with it. */
:root[data-text-size="large"]  { font-size: 112.5%; }
:root[data-text-size="xlarge"] { font-size: 125%; }

/* Extra contrast: push text and lines toward maximum separation, per theme. */
:root[data-contrast="high"] {
  --ink: #000000; --dim: #23262d; --faint: #3a3d44; --line: #86857b; --acc-link: #063c36;
}
@media (prefers-color-scheme: dark) {
  :root[data-contrast="high"] {
    --ink: #ffffff; --dim: #e9e9e2; --faint: #cdcfc8; --line: #5c5e5e; --acc-link: #93e8d8;
  }
}
:root[data-theme="light"][data-contrast="high"] {
  --ink: #000000; --dim: #23262d; --faint: #3a3d44; --line: #86857b; --acc-link: #063c36;
}
:root[data-theme="dark"][data-contrast="high"] {
  --ink: #ffffff; --dim: #e9e9e2; --faint: #cdcfc8; --line: #5c5e5e; --acc-link: #93e8d8;
}
:root[data-contrast="high"] a { text-decoration: underline; }

/* ── base ───────────────────────────────────────────────────────────── */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}
/* The reduce-motion preference mirrors the OS setting, but on demand. */
:root[data-motion="off"] { scroll-behavior: auto; }
:root[data-motion="off"] * {
  animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
}
/* The hero branch self-draws with a delay, so the blanket rule above would
   leave it stuck at its undrawn (invisible) start. Force its finished state. */
:root[data-motion="off"] .hero-branch .b-main,
:root[data-motion="off"] .hero-branch .b-twig {
  stroke-dashoffset: 0 !important; animation: none !important;
}
:root[data-motion="off"] .hero-branch .b-node { opacity: 0.3 !important; animation: none !important; }

/* ── dyslexia-friendly type ──────────────────────────────────────────────
   Two parts, and the second is the one carrying the evidence. The stack picks
   up OpenDyslexic or Atkinson Hyperlegible when the reader has them installed
   (many do) and otherwise lands on Verdana/Tahoma — wide, open, high x-height,
   the faces the British Dyslexia Association's style guide names. No webfont:
   this site ships system fonts only, and one option is no reason to break that.
   The spacing is what studies reproduce: looser letter, word and line spacing
   and a shorter measure. Serif display faces give way to the same stack, and
   the negative heading tracking is undone — it works against exactly this. */
:root[data-font="dyslexic"] {
  --font-sans: "OpenDyslexic", "Atkinson Hyperlegible", Verdana, Tahoma, "Trebuchet MS", sans-serif;
  --font-serif: "OpenDyslexic", "Atkinson Hyperlegible", Verdana, Tahoma, "Trebuchet MS", sans-serif;
}
:root[data-font="dyslexic"] body {
  letter-spacing: 0.05em;
  word-spacing: 0.16em;
  line-height: 1.7;
}
:root[data-font="dyslexic"] h1,
:root[data-font="dyslexic"] h2,
:root[data-font="dyslexic"] h3 { letter-spacing: 0.01em; line-height: 1.3; }
:root[data-font="dyslexic"] p,
:root[data-font="dyslexic"] li { max-width: 62ch; }
/* Compact interface labels keep normal tracking: the extra spacing buys nothing
   on a two-word button and, at 375px, pushed the header button off-screen. */
:root[data-font="dyslexic"] .btn,
:root[data-font="dyslexic"] .site-nav,
:root[data-font="dyslexic"] .foot-nav,
:root[data-font="dyslexic"] .a11y-seg button,
:root[data-font="dyslexic"] .badge { letter-spacing: normal; word-spacing: normal; }

/* ── calm view ───────────────────────────────────────────────────────────
   For readers who are quickly overloaded, and for anyone who wants the page to
   simply hold still. It is deliberately not a "mode" for a diagnosis: it names
   what it does. Everything decorative or unprompted goes — the drawn branches,
   the marquee, hover lift, shadows, the header that hides itself while you
   scroll. Content, contrast and layout stay exactly as they are, so nothing is
   hidden from anyone who turns it on. Implies reduce-motion (set in JS). */
:root[data-calm="on"] * {
  animation: none !important;
  transition: none !important;
  scroll-behavior: auto !important;
}
:root[data-calm="on"] .hero-branch,
:root[data-calm="on"] .flow-vine,
:root[data-calm="on"] .foot-vine { display: none !important; }
/* the header must not move on its own */
:root[data-calm="on"] .site-header { transform: none !important; }
/* Nothing lifts or casts a shadow under the pointer. Named per element on
   purpose: a blanket transform/box-shadow reset would knock the fanned cards
   out of their layout (they are positioned with transforms) and strip the
   focus ring off the form fields, which is drawn with a box-shadow. */
:root[data-calm="on"] .btn:hover,
:root[data-calm="on"] .case-card:hover,
:root[data-calm="on"] .service-teaser:hover { transform: none !important; box-shadow: none !important; }

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  /* rem-based so the text-size preference (which scales the root font-size)
     carries through to the body copy and everything sized in rem. */
  font-size: 1.125rem;
  line-height: 1.62;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  padding-left: var(--safe-l);
  padding-right: var(--safe-r);
  transition: background 0.3s ease, color 0.3s ease;
}

a { color: var(--acc-link); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Links embedded in running text must be distinguishable without relying on
   colour (WCAG 1.4.1 / axe link-in-text-block): the accent link colour does not
   reach 3:1 against body ink, so prose links carry a persistent underline. UI
   links (nav, cards, CTAs) live outside <p> and keep the clean no-underline look. */
p a { text-decoration: underline; text-underline-offset: 0.15em; }
img { max-width: 100%; height: auto; display: block; }
em { font-style: normal; color: var(--acc-link); font-weight: 600; }

h1, h2, h3 { font-family: var(--font-serif); font-weight: 700; letter-spacing: -0.02em; line-height: 1.06; }

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

.skip-link {
  position: absolute; left: 0; top: 0; z-index: 200;
  background: var(--acc); color: var(--acc-ink);
  padding: 0.7em 1.1em; font-weight: 700; border-radius: 0 0 var(--rad) 0;
  transform: translateY(-120%);
}
.skip-link:focus { transform: translateY(0); text-decoration: none; }

.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding-left: clamp(1.3rem, 5vw, 3rem);
  padding-right: clamp(1.3rem, 5vw, 3rem);
  width: 100%;
}

/* ── shared type ────────────────────────────────────────────────────── */
.kicker {
  font-family: var(--font-sans);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.76rem;
  font-weight: 700;
  color: var(--acc-link);
  margin: 0 0 1.3rem;
}
.section-title { font-size: clamp(2rem, 4.5vw, 3.2rem); margin: 0; text-wrap: balance; }
.section-lead {
  font-family: var(--font-sans);
  font-size: clamp(1.05rem, 1.8vw, 1.28rem);
  color: var(--dim);
  max-width: 54ch;
  margin: 1.1rem 0 0;
  line-height: 1.6;
}

/* ── buttons ────────────────────────────────────────────────────────── */
.btn {
  display: inline-block;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 0.98rem;
  color: var(--acc-ink);
  background: var(--acc);
  border: 0;
  border-radius: var(--rad);
  padding: 0.82em 1.5em;
  cursor: pointer;
  transition: filter 0.14s ease, transform 0.14s ease;
}
.btn:hover { text-decoration: none; filter: brightness(1.06); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-big { font-size: 1.12rem; padding: 0.95em 1.8em; }
.btn-sm { font-size: 0.86rem; padding: 0.6em 1.05em; }
.link-out { font-weight: 700; font-size: 0.98rem; color: var(--acc-link); }

/* ── badges & tags ──────────────────────────────────────────────────── */
.badge {
  display: inline-block; font-family: var(--font-sans);
  font-size: 0.74rem; font-weight: 700; letter-spacing: 0.02em;
  padding: 0.32em 0.8em; border-radius: 999px; border: 1px solid var(--line);
  white-space: nowrap;
}
.badge-live { color: var(--ok-ink); border-color: color-mix(in srgb, var(--ok) 45%, transparent); background: color-mix(in srgb, var(--ok) 10%, transparent); }
.badge-experiment { color: var(--acc-link); border-color: color-mix(in srgb, var(--acc) 40%, transparent); background: var(--acc-soft); }

.tags { list-style: none; display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0; margin: 1.3rem 0 0; }
.tags li {
  font-size: 0.82rem; font-weight: 600; color: var(--dim);
  background: var(--bg-soft); border: 1px solid var(--line);
  border-radius: 8px; padding: 0.35em 0.75em;
}

/* ── header ─────────────────────────────────────────────────────────── */
/* Pinned for good: the header used to hide itself on the way down, which meant
   the display settings and the navigation were out of reach exactly when a
   reader was deep in a page and most likely to want them. It stays put. */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
  transition: background 0.3s ease;
}
.header-inner { display: flex; align-items: center; gap: 1.5rem; min-height: var(--header-h); padding-top: 0.5rem; padding-bottom: 0.5rem; }
.brand { display: inline-flex; align-items: center; gap: 0.6rem; color: var(--ink); }
.brand:hover { text-decoration: none; }
.brand-mark { width: 16px; height: 16px; border-radius: 4px; background: var(--acc); box-shadow: inset 0 0 0 3px var(--bg); outline: 1.5px solid var(--acc); }
.brand-name { font-family: var(--font-serif); font-size: 1.32rem; font-weight: 700; letter-spacing: -0.02em; }
/* Site-wide "still being built" marker, in the sticky header so it never
   scrolls away. Subtle but legible: a soft accent dot plus the label in a quiet
   pill. The dot is shared with nowhere else now, but kept as its own class in
   case the marker moves again. */
.hdr-wip { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.22rem 0.6rem; border: 1px solid var(--line); border-radius: 100px; color: var(--dim); font-size: 0.72rem; font-weight: 600; line-height: 1; white-space: nowrap; }
.wip-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--acc); box-shadow: 0 0 0 3px var(--acc-soft); flex: none; }
.site-nav { margin-left: auto; }
.site-nav ul { list-style: none; display: flex; gap: 1.6rem; margin: 0; padding: 0; }
.site-nav a { color: var(--dim); font-size: 0.92rem; font-weight: 600; }
.site-nav a:hover { color: var(--ink); text-decoration: none; }
/* Hamburger — hidden until the nav collapses (see the 760px breakpoint). Same
   round shell as the theme/display toggles; the bars morph to an × when open. */
.nav-toggle { display: none; width: 38px; height: 38px; border-radius: 50%; background: transparent; border: 1px solid var(--line); place-items: center; cursor: pointer; color: var(--ink); transition: border-color 0.14s ease, background 0.14s ease; }
.nav-toggle:hover { border-color: var(--acc); background: var(--acc-soft); }
.nav-toggle[aria-expanded="true"] { border-color: var(--acc); background: var(--acc-soft); }
.nav-toggle-bars { position: relative; }
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after { display: block; width: 18px; height: 2px; border-radius: 2px; background: var(--ink); transition: transform 0.18s ease, background-color 0.18s ease; }
.nav-toggle-bars::before, .nav-toggle-bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle-bars::before { top: -6px; }
.nav-toggle-bars::after { top: 6px; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after { transform: translateY(-6px) rotate(-45deg); }
/* The language switch has a second home at the foot of the mobile dropdown;
   that copy is hidden on desktop, where the header-actions copy carries it. */
.nav-lang { display: none; }
.header-actions { display: flex; align-items: center; gap: 0.9rem; }
.theme-toggle { width: 38px; height: 38px; border-radius: 50%; background: transparent; border: 1px solid var(--line); display: inline-grid; place-items: center; cursor: pointer; transition: border-color 0.14s ease, background 0.14s ease; }
.theme-toggle:hover { border-color: var(--acc); background: var(--acc-soft); }
.theme-icon { width: 17px; height: 17px; border-radius: 50%; border: 2px solid var(--ink); background: linear-gradient(90deg, var(--ink) 0 50%, transparent 50% 100%); }

/* ── language switch (NL / EN) ──────────────────────────────────────────
   A compact segmented pill in the header actions, matching the round toggles.
   Each language is flag + short code; the active one is a marked <span>, the
   other a real <a> to the same page in that language (works without JS). */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  border: 0; overflow: hidden; white-space: nowrap; clip: rect(0 0 0 0);
  clip-path: inset(50%);
}
.lang-switch {
  display: inline-flex; align-items: stretch; height: 38px;
  border: 1px solid var(--line); border-radius: 999px; overflow: hidden;
}
.lang-opt {
  display: inline-flex; align-items: center; gap: 0.36rem;
  padding: 0 0.62rem; color: var(--dim); text-decoration: none;
  font-size: 0.8rem; font-weight: 600; line-height: 1;
  transition: background 0.14s ease, color 0.14s ease;
}
.lang-opt + .lang-opt { border-left: 1px solid var(--line); }
.lang-opt .flag {
  display: block; width: 20px; height: 14px; border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
}
.lang-opt .lang-code { letter-spacing: 0.02em; }
a.lang-opt:hover { color: var(--ink); background: var(--acc-soft); text-decoration: none; }
a.lang-opt:focus-visible { outline: 2px solid var(--acc); outline-offset: -2px; }
.lang-opt.is-current { color: var(--ink); background: var(--acc-soft); cursor: default; }
/* Below the nav breakpoint the flag alone carries it — the accessible name
   still rides on the link's aria-label and the current option's hidden text. */
@media (max-width: 420px) { .lang-opt .lang-code { display: none; } .lang-opt { padding: 0 0.5rem; } }
/* Once the nav hides it no longer carries the margin that pushed the controls
   right, so hand that job to the actions — the wip pill stays by the brand, the
   toggles keep to the far edge. */
/* Below this width the inline nav collapses behind the hamburger and reopens
   as a disclosure dropdown anchored under the sticky header. Without JS the
   toggle is inert and navigation falls to the footer (as it did before). */
@media (max-width: 760px) {
  .header-inner { gap: 0.7rem; }
  .nav-toggle { display: inline-grid; margin-left: auto; }
  .site-nav {
    position: absolute; top: calc(100% + 0.4rem); right: 0.8rem; z-index: 300;
    display: none; margin-left: 0;
    min-width: 210px; max-width: calc(100vw - 1.6rem);
    background: var(--bg-card); border: 1px solid var(--line);
    border-radius: var(--rad-lg); box-shadow: 0 20px 50px -24px rgba(0, 0, 0, 0.45);
    padding: 0.5rem;
  }
  .site-nav.is-open { display: block; }
  .site-nav ul { flex-direction: column; gap: 0; align-items: stretch; }
  .site-nav a { display: block; padding: 0.62rem 0.7rem; border-radius: var(--rad); font-size: 1rem; }
  .site-nav a:hover { background: var(--acc-soft); }
  .site-nav a[aria-current="page"] { background: var(--acc-soft); }
  /* The language switch drops to the foot of the menu here; the header copy
     yields its space to the display/theme controls, which stay one tap away. */
  .header-actions .lang-switch { display: none; }
  .nav-lang { display: block; margin-top: 0.35rem; padding: 0.5rem 0.5rem 0.15rem; border-top: 1px solid var(--line); }
  .nav-lang .lang-switch { display: inline-flex; }
  /* The "work in progress" pill shrinks to just its dot to make room; the full
     label stays in the accessibility tree (visually hidden, not removed) and in
     the title, so screen readers still announce it. */
  .hdr-wip { border: none; padding: 0; }
  .hdr-wip span[lang] {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    border: 0; overflow: hidden; white-space: nowrap; clip: rect(0 0 0 0);
    clip-path: inset(50%);
  }
}
/* At the 320px floor WCAG 1.4.10 asks for, the wordmark is what no longer fits
   next to the controls — it overflowed there even at default text size. The
   mark keeps the link (and the name stays in the accessibility tree, so the
   link is still announced as "Systemsoft"). */
@media (max-width: 360px) {
  .brand-name {
    position: absolute; width: 1px; height: 1px; margin: -1px;
    padding: 0; border: 0; overflow: hidden; white-space: nowrap;
    clip: rect(0 0 0 0); clip-path: inset(50%);
  }
}

/* ── display-preferences panel ──────────────────────────────────────── */
.a11y { position: relative; display: inline-flex; }
.a11y-toggle {
  width: 38px; height: 38px; border-radius: 50%; background: transparent;
  border: 1px solid var(--line); display: inline-grid; place-items: center;
  cursor: pointer; color: var(--ink);
  transition: border-color 0.14s ease, background 0.14s ease;
}
.a11y-toggle:hover { border-color: var(--acc); background: var(--acc-soft); }
.a11y-icon { font-family: var(--font-serif); font-weight: 700; font-size: 1rem; line-height: 1; }
.a11y-icon sup { font-size: 0.62em; }
.a11y-toggle[aria-expanded="true"] { border-color: var(--acc); background: var(--acc-soft); }

.a11y-panel {
  position: absolute; top: calc(100% + 0.6rem); right: 0; z-index: 300;
  width: 250px; max-width: calc(100vw - 2rem);
  background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--rad-lg);
  box-shadow: 0 20px 50px -24px rgba(0,0,0,0.45);
  padding: 1.1rem 1.15rem 1rem;
}
.a11y-panel[hidden] { display: none; }
.a11y-title { font-family: var(--font-serif); font-weight: 700; font-size: 1.1rem; margin: 0 0 0.9rem; color: var(--ink); }
.a11y-group { margin: 0 0 0.9rem; }
.a11y-label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--ink); margin: 0 0 0.45rem; }
.a11y-seg { display: flex; gap: 0.35rem; }
.a11y-seg button {
  flex: 1; font: inherit; font-size: 0.82rem; cursor: pointer;
  padding: 0.5em 0.3em; border: 1px solid var(--line); border-radius: var(--rad);
  background: var(--bg); color: var(--ink);
  transition: border-color 0.14s ease, background 0.14s ease;
}
.a11y-seg button:hover { border-color: var(--acc); }
.a11y-seg button[aria-pressed="true"] { background: var(--acc); color: var(--acc-ink); border-color: var(--acc); }
.a11y-check { display: flex; align-items: center; gap: 0.55rem; font-size: 0.92rem; color: var(--ink); margin: 0 0 0.6rem; cursor: pointer; }
.a11y-check input { width: 1.05em; height: 1.05em; accent-color: var(--acc); cursor: pointer; }
.a11y-note { font-size: 0.78rem; color: var(--faint); margin: 0.7rem 0 0; }
@media (max-width: 760px) { .a11y-panel { position: fixed; top: calc(var(--header-h) + 0.4rem); right: 0.8rem; } }

/* ── hero ───────────────────────────────────────────────────────────── */
.hero { position: relative; overflow: hidden; padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(2.5rem, 5vw, 4rem); }
.hero-inner { position: relative; }
.hero-title { max-width: 20ch; font-size: clamp(2.9rem, 8vw, 5.4rem); line-height: 1.0; margin: 0 0 1.4rem; text-wrap: balance; }
.hero-lead { font-size: clamp(1.1rem, 2.2vw, 1.42rem); color: var(--dim); line-height: 1.55; max-width: 46ch; margin: 0 0 2.2rem; }
.hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.6rem; }

/* The drawn branch — one tapering ink line on the hero's right flank.
   Draws itself once on load; static under prefers-reduced-motion. */
.hero-branch { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.hero-branch path { stroke: var(--acc); fill: none; stroke-linecap: round; }
.hero-branch .b-under { stroke-width: 14; opacity: 0.08; }
.hero-branch .b-main { stroke-width: 3.5; opacity: 0.26; }
.hero-branch .b-twig { stroke-width: 2; opacity: 0.26; }
.hero-branch .b-node { fill: var(--acc); stroke: none; opacity: 0.3; }
@media (prefers-reduced-motion: no-preference) {
  .hero-branch .b-main { stroke-dasharray: 620; stroke-dashoffset: 620; animation: branch-draw 2.2s cubic-bezier(0.4, 0, 0.2, 1) 0.35s forwards; }
  .hero-branch .b-twig { stroke-dasharray: 175; stroke-dashoffset: 175; animation: branch-draw 0.9s ease-out 2s forwards; }
  .hero-branch .b-node { opacity: 0; animation: branch-node 0.5s ease-out 2.5s forwards; }
}
@keyframes branch-draw { to { stroke-dashoffset: 0; } }
@keyframes branch-node { to { opacity: 0.3; } }
@media (max-width: 640px) { .hero-branch { display: none; } }

/* ── page branch ────────────────────────────────────────────────────────
   A quiet teal line that draws itself as you scroll through a page's flow,
   splitting into dendrites at knots on the line — a stylised nod to the
   branching mindmap motif. Decorative and aria-hidden; built by app.js only
   when motion is allowed. On the home the flow sections go background-less so
   the branch weaves consistently behind them (the cards stay solid islands). */
.vine-flow { position: relative; }
.flow-vine { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; overflow: visible; }
.vine-flow > section, .vine-flow > .section { position: relative; z-index: 1; }
/* Banded sections lose their fill inside the flow so the branch stays visible
   behind them; the cards themselves keep their own background and read as
   solid islands over the line. */
.vine-flow .pillars-strip,
.vine-flow .approach,
.vine-flow .family-band,
.vine-flow .contact-band { background: transparent; }

.flow-vine .vine-main, .foot-vine .vine-main { fill: none; stroke: var(--acc); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; opacity: 0.34; }
.flow-vine .vine-arc, .foot-vine .vine-arc { fill: none; stroke: var(--acc); stroke-linecap: round; stroke-dasharray: var(--tl); stroke-dashoffset: var(--tl); }
.flow-vine .vine-arc.grown, .foot-vine .vine-arc.grown { stroke-dashoffset: 0; transition: stroke-dashoffset 1.15s cubic-bezier(0.16, 0.7, 0.3, 1); }
.flow-vine .vine-node, .foot-vine .vine-node { fill: var(--acc); opacity: 0; }
.flow-vine .vine-node.lit, .foot-vine .vine-node.lit { opacity: 0.72; }
.flow-vine .vine-node, .flow-vine .vine-arc,
.foot-vine .vine-node, .foot-vine .vine-arc { transition: opacity 0.45s ease, r 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
@media (max-width: 900px) { .flow-vine { display: none; } }

/* The branch runs on into the footer, where it forks once more and each twig
   ends at one of the footer links. Drawn by app.js in the same pass as the
   flow vine, so it only exists when motion is allowed and the window is wide. */
.site-foot { position: relative; }
/* overflow must clip here: the footer draws the tail of the flow's stem path,
   shifted up by the flow height, and everything above the footer is the flow's
   own business — showing it would double the line over the page above. */
.foot-vine { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; overflow: hidden; }
.site-foot .foot-inner { position: relative; z-index: 1; }
@media (max-width: 900px) { .foot-vine { display: none; } }

/* ── pillars strip ──────────────────────────────────────────────────── */
.pillars-strip { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--bg-soft); }
/* auto-fit rather than a fixed column count: the strip carries five pillars
   now and should not break when one is added or dropped. min(100%, …) keeps a
   single column from overflowing a narrow screen. 210px is chosen against the
   measured track width (1120px inside .wrap at 1280): it keeps all five on one
   row on a desktop. Around 900px they fall to 4+1, which is simply what a
   five-item grid does — the fixed breakpoints below take over from 760px. */
.pillars-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
.pillar { display: flex; flex-direction: column; gap: 0.35rem; padding: 1.7rem clamp(1rem, 2.2vw, 1.7rem); border-left: 1px solid var(--line); }
.pillar:first-child { border-left: 0; padding-left: 0; }
.pillar-label { font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; font-weight: 700; color: var(--acc-link); }
.pillar-title { font-size: 1rem; font-weight: 700; color: var(--ink); }
.pillar-note { font-size: 0.82rem; color: var(--dim); }
@media (max-width: 760px) {
  .pillars-grid { grid-template-columns: 1fr 1fr; }
  .pillar { padding: 1.3rem 1.1rem; }
  .pillar:first-child { padding-left: 1.1rem; border-left: 1px solid var(--line); }
  .pillar:nth-child(odd) { border-left: 0; padding-left: 0; }
}
@media (max-width: 440px) {
  .pillars-grid { grid-template-columns: 1fr; }
  .pillar, .pillar:first-child, .pillar:nth-child(odd) { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); }
  .pillar:first-child { border-top: 0; }
}

/* Marquee mode (JS enhancement): the strip becomes one slow right-to-left
   band. The list is duplicated by app.js for a seamless loop; it pauses on
   hover/focus and via the explicit pause button, and never starts under
   prefers-reduced-motion (app.js checks before enhancing). */
.pillars-strip { position: relative; }
.is-marquee .pillars-viewport { display: flex; overflow: hidden; }
.is-marquee .pillars-grid {
  /* width:max-content beats .wrap's width:100% — the track must be as wide
     as its items, or the duplicate slides over the overflow. */
  display: flex; flex: none; width: max-content; min-width: 100%;
  max-width: none; margin: 0; padding: 0;
  justify-content: space-around;
  animation: pillars-scroll 44s linear infinite;
}
.is-marquee .pillar,
.is-marquee .pillar:first-child,
.is-marquee .pillar:nth-child(odd) {
  flex: none; border-top: 0; border-left: 1px solid var(--line);
  padding: 1.6rem clamp(1.6rem, 4vw, 3rem);
}
.is-marquee:hover .pillars-grid,
.is-marquee:focus-within .pillars-grid,
.is-marquee.is-paused .pillars-grid { animation-play-state: paused; }
@keyframes pillars-scroll { to { transform: translateX(-100%); } }
.marquee-toggle {
  position: absolute; right: 0.7rem; bottom: 0.7rem;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--bg-card); color: var(--dim);
  font-size: 0.55rem; line-height: 1; cursor: pointer; padding: 0;
}
.marquee-toggle:hover { color: var(--ink); border-color: var(--acc); }

/* The same control on the case clips: they loop by themselves, so there has to
   be a way to stop them (WCAG 2.2.2). Top-right, clear of the caption; the
   figure/card body is the positioning context, set here rather than inline so
   the fanned deck keeps its own absolute placement. */
.media, .mf-body { position: relative; }
.clip-toggle {
  position: absolute; right: 0.7rem; top: 0.7rem; z-index: 2;
  width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--bg-card); color: var(--dim);
  font-size: 0.6rem; line-height: 1; cursor: pointer; padding: 0;
}
.clip-toggle:hover { color: var(--ink); border-color: var(--acc); }

/* ── section rhythm ─────────────────────────────────────────────────── */
.section { padding: clamp(3.5rem, 9vh, 7rem) 0; }
.section + .section { border-top: 1px solid var(--line); }

/* ── services ───────────────────────────────────────────────────────── */
/* Grid items default to min-content width, so at the largest text size a long
   compound like "toegankelijkheid" made the card wider than the screen. Let
   long words break and stop the items claiming their min-content width. */
.services-grid > *, .cases-grid > *, .principles-grid > * { min-width: 0; }
h1, h2, h3, p, li, .service-label, .case-title { overflow-wrap: break-word; }
/* A button label is content too: at the largest text size with the wide
   dyslexia face, a long call to action grew past a 320px screen. */
.btn { max-width: 100%; overflow-wrap: break-word; }

.services-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.4rem; margin-top: clamp(2rem, 4vw, 3rem); }
.service { background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--rad-lg); padding: clamp(1.6rem, 2.5vw, 2.1rem); display: flex; flex-direction: column; }
.service-label { font-family: var(--font-serif); font-size: 1.4rem; margin: 0 0 0.7rem; color: var(--ink); }
.service-claim { font-weight: 600; color: var(--ink); margin: 0 0 0.9rem; font-size: 1.02rem; }
.service-body { color: var(--dim); margin: 0 0 1.3rem; font-size: 0.98rem; }
.service-points { list-style: none; margin: auto 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.service-points li { position: relative; padding-left: 1.4rem; font-size: 0.9rem; color: var(--ink); }
.service-points li::before { content: ""; position: absolute; left: 0; top: 0.5em; width: 7px; height: 7px; border-radius: 2px; background: var(--acc); }
@media (max-width: 880px) { .services-grid { grid-template-columns: 1fr; } }

/* ── approach ───────────────────────────────────────────────────────── */
.approach { background: var(--bg-soft); }
.principles-grid { list-style: none; margin: clamp(2rem, 4vw, 3rem) 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 1.6rem 2.4rem; }
.principle { padding-top: 1.4rem; border-top: 2px solid var(--acc); }
.principle-title { font-size: 1.24rem; margin: 0 0 0.5rem; color: var(--ink); }
.principle-body { color: var(--dim); margin: 0; font-size: 0.98rem; }
@media (max-width: 720px) { .principles-grid { grid-template-columns: 1fr; } }

/* ── delivery / hosting routes ──────────────────────────────────────── */
.routes-grid { list-style: none; margin: clamp(2rem, 4vw, 3rem) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; }
.route { background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--rad-lg); padding: 1.5rem 1.6rem; display: flex; flex-direction: column; }
.route-title { font-size: 1.2rem; margin: 0 0 0.6rem; color: var(--ink); }
.route-body { color: var(--dim); margin: 0; font-size: 0.98rem; }
.delivery-guarantee { margin: clamp(1.8rem, 3.5vw, 2.6rem) 0 0; font-size: clamp(1.05rem, 1.8vw, 1.25rem); color: var(--ink); max-width: 62ch; text-wrap: pretty; }
.delivery-guarantee em { color: var(--acc-link); }
@media (max-width: 820px) { .routes-grid { grid-template-columns: 1fr; } }

/* ── work / cases ───────────────────────────────────────────────────── */
.work-body { color: var(--dim); margin: 1.2rem 0 0; font-size: 1.05rem; max-width: 60ch; }
.cases-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.2rem; margin-top: clamp(2rem, 4vw, 3rem); }
.case-card {
  display: flex; flex-direction: column;
  background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--rad-lg);
  overflow: hidden; color: var(--ink);
  transition: border-color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
}
.case-card:hover { text-decoration: none; border-color: var(--acc); transform: translateY(-2px); box-shadow: 0 16px 40px -24px rgba(0,0,0,0.4); }
/* Ink miniature: a small line drawing per case, in the accent ink. */
.case-thumb {
  height: 96px; background: var(--acc-soft); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
}
.case-thumb svg { width: 56%; height: 68%; }
.case-thumb path, .case-thumb circle, .case-thumb rect,
.case-thumb line, .case-thumb polygon, .case-thumb ellipse {
  stroke: var(--acc); fill: none; stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
  /* Marks are per-mark scaled to a shared size; keep the line weight uniform so
     an up/down-scaled mark does not render thicker/thinner than its neighbours. */
  vector-effect: non-scaling-stroke;
}
.case-thumb .mark-fill { fill: var(--acc); stroke: none; }
.case-body { display: flex; flex-direction: column; gap: 0.7rem; padding: 1.35rem 1.5rem 1.5rem; flex: 1; }
.case-head { display: flex; align-items: center; justify-content: space-between; gap: 0.8rem; }
.case-title { font-family: var(--font-serif); font-size: 1.25rem; font-weight: 700; }
.case-claim { color: var(--dim); font-size: 0.95rem; flex: 1; }
.case-more { color: var(--acc-link); font-weight: 700; font-size: 0.9rem; margin-top: auto; }
@media (max-width: 880px) { .cases-grid { grid-template-columns: 1fr; } }

/* ── the c-family band: one solution, three systems ─────────────────── */
.family-band {
  background: var(--bg-soft);
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  scroll-margin-top: 5rem; /* the header is sticky; keep the anchor visible */
}
.family-story { max-width: 70ch; margin-top: clamp(1.2rem, 2.5vw, 1.8rem); }
.family-story p { color: var(--dim); margin: 0 0 1rem; }
.family-story p em { color: var(--acc-link); }
/* cross-link strip on the family case pages */
.family-note {
  max-width: 70ch; margin: 0 0 clamp(2rem, 4vw, 3rem);
  padding: 0.85em 1.15em;
  background: var(--acc-soft); border-left: 3px solid var(--acc);
  border-radius: var(--rad);
}
.family-note p { margin: 0; font-size: 0.95rem; color: var(--ink); }

/* ── contact ────────────────────────────────────────────────────────── */
.contact-inner { max-width: 620px; }
.contact-form { margin-top: clamp(1.8rem, 3vw, 2.6rem); display: flex; flex-direction: column; gap: 1.2rem; }
.field { display: flex; flex-direction: column; gap: 0.45rem; margin: 0; }
.field label { font-weight: 600; font-size: 0.92rem; color: var(--ink); }
.contact-form input, .contact-form textarea {
  font-family: var(--font-sans); font-size: 1rem; color: var(--ink);
  background: var(--bg-card); border: 1px solid var(--line); border-radius: var(--rad);
  padding: 0.75em 0.9em; width: 100%;
  transition: border-color 0.14s ease, box-shadow 0.14s ease;
}
.contact-form input:focus, .contact-form textarea:focus { outline: none; border-color: var(--acc); box-shadow: 0 0 0 3px var(--acc-soft); }
.contact-form textarea { resize: vertical; min-height: 140px; }
.contact-form .btn-big { align-self: flex-start; }
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form-status { margin: 0; padding: 0.85em 1em; border-radius: var(--rad); font-size: 0.95rem; font-weight: 600; }
.form-status[data-tone="ok"] { background: var(--acc-soft); color: var(--acc-link); border: 1px solid var(--acc); }
.form-status[data-tone="err"] { background: color-mix(in srgb, var(--err) 12%, transparent); color: var(--err); border: 1px solid color-mix(in srgb, var(--err) 45%, transparent); }
.contact-fallback { font-size: 0.92rem; color: var(--dim); margin: 0.4rem 0 0; }

/* ── footer ─────────────────────────────────────────────────────────── */
.site-foot { border-top: 1px solid var(--line); background: var(--bg-soft); }
.foot-inner { display: grid; grid-template-columns: 1fr; gap: clamp(2rem, 4vw, 3rem); padding-top: clamp(2.5rem, 5vw, 4rem); padding-bottom: clamp(2.5rem, 5vw, 4rem); }
.foot-brand { display: flex; flex-direction: column; gap: 0.4rem; }
.foot-name { font-family: var(--font-serif); font-size: 1.3rem; font-weight: 700; margin: 0; color: var(--ink); }
.foot-tag { color: var(--dim); margin: 0; font-size: 0.95rem; max-width: 42ch; }
/* Two mirrored columns hugging the centre line: the branch that runs through
   the page arrives down the middle and forks one last time, half the twigs
   left, half right. Ragged edges face outward so the link ends line up on
   either side of the trunk — that is where the twigs attach. It stays one
   list; the halves are column flow (--foot-rows travels with the markup). */
/* Equal halves, not auto-width columns: the trunk comes down the middle of the
   page, so the gutter has to be centred there too. Sizing the columns to their
   content (the legal links are twice as long as the nav ones) walks the gutter
   off-centre and leaves one bough visibly shorter than the other. */
.foot-nav ul { list-style: none; margin: 0; padding: 0; display: grid; grid-auto-flow: column; grid-template-columns: 1fr 1fr; grid-template-rows: repeat(var(--foot-rows, 4), auto); column-gap: clamp(3rem, 14vw, 12rem); row-gap: 0.7rem; }
.foot-nav li { text-align: left; }
.foot-nav li.foot-l { text-align: right; }
.foot-nav a { color: var(--dim); font-weight: 600; font-size: 0.95rem; }
.foot-nav a:hover { color: var(--ink); }
.foot-credit { grid-column: 1 / -1; margin: 0; padding-top: 1.5rem; border-top: 1px solid var(--line); color: var(--faint); font-size: 0.85rem; }
/* Below the branch's own breakpoint there is no trunk to hang the columns on,
   so they collapse back to one plain left-aligned list. */
@media (max-width: 900px) {
  .foot-nav ul { grid-auto-flow: row; grid-template-columns: 1fr; grid-template-rows: none; row-gap: 0.6rem; }
  .foot-nav li, .foot-nav li.foot-l { text-align: left; }
}

/* ── sub-page hero ──────────────────────────────────────────────────── */
.page-hero { padding: clamp(3rem, 7vw, 5rem) 0 clamp(1.6rem, 3vw, 2.6rem); border-bottom: 1px solid var(--line); }
.page-title { font-size: clamp(2.4rem, 6vw, 4rem); margin: 0 0 1rem; text-wrap: balance; }
.page-lead { font-size: clamp(1.1rem, 2vw, 1.35rem); color: var(--dim); max-width: 58ch; margin: 0; line-height: 1.55; }

/* active nav item */
.site-nav a[aria-current="page"] { color: var(--acc-link); }

/* service teaser (home) */
.service-teaser { color: var(--ink); }
.service-teaser:hover { text-decoration: none; border-color: var(--acc); transform: translateY(-2px); box-shadow: 0 16px 40px -24px rgba(0,0,0,0.4); }
.service-more { color: var(--acc-link); font-weight: 700; font-size: 0.9rem; margin-top: auto; }

/* "more" link after a grid */
.section-more { display: inline-block; margin-top: clamp(1.5rem, 3vw, 2.2rem); }

/* approach teaser + contact band (home) */
.approach-teaser-inner, .contact-band-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem 2.5rem; flex-wrap: wrap;
}
.approach-teaser-inner > div, .contact-band-inner > div { max-width: 58ch; }
.contact-band { background: var(--bg-soft); }
.approach-lead { margin-bottom: clamp(1.8rem, 4vw, 2.8rem); }

/* ── case detail & process pages ────────────────────────────────────── */
.proj-nav { padding: 1.6rem 0 0; }
.proj-nav a { font-weight: 600; font-size: 0.95rem; }
.project { padding: clamp(1.5rem, 4vw, 2.5rem) 0 clamp(3rem, 6vw, 5rem); }
.proj-hero { padding: clamp(1.5rem, 4vw, 2.5rem) 0 clamp(2rem, 4vw, 3rem); border-bottom: 1px solid var(--line); margin-bottom: clamp(2rem, 4vw, 3rem); }
.proj-hero h1 { font-size: clamp(2.2rem, 6vw, 3.6rem); margin: 0 0 1rem; }
.proj-hero .lead { font-size: clamp(1.1rem, 2vw, 1.35rem); color: var(--dim); margin: 1.2rem 0 0; max-width: 54ch; }
.proj-section { margin: 0 0 clamp(2.5rem, 5vw, 3.5rem); max-width: 70ch; }
.proj-section h2 { font-size: clamp(1.5rem, 3vw, 2.1rem); margin: 0 0 1rem; }
.proj-section p { color: var(--dim); margin: 0 0 1rem; }
.proj-section p em { color: var(--acc-link); }
.proc-list { color: var(--dim); padding-left: 1.3rem; display: flex; flex-direction: column; gap: 0.7rem; }
.proc-list li { padding-left: 0.3rem; }
/* Trust/legal statements (accessibility, privacy & cookies) — reuse the
   .proj-section typography (70ch measure, linked em). Calm accent-square
   bullets for the enumerated lists. */
.statement-points { list-style: none; margin: 0 0 1rem; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.statement-points li { position: relative; padding-left: 1.5rem; color: var(--dim); }
.statement-points li::before { content: ""; position: absolute; left: 0; top: 0.55em; width: 7px; height: 7px; border-radius: 2px; background: var(--acc); }
.statement-section .btn { margin-top: 0.4rem; }
.statement-updated { color: var(--faint); font-size: 0.9rem; font-style: italic; margin: clamp(1rem, 3vw, 2rem) 0 0; }

.proj-media { max-width: 100%; }
.media-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 1.6rem 1.2rem; align-items: start; margin: 1.5rem 0; }
/* text-based demos (terminal / TUI fan) always want the full row */
.media-grid .media-term, .media-grid .media-tui { grid-column: 1 / -1; margin: 0; }
.media { margin: 0; }
/* Screenshots range from wide dashboards to tall phone captures. Never stretch
   them to the column width; fit within it and cap the height so a tall capture
   can't run away down the page. */
.media img { display: block; width: auto; height: auto; max-width: 100%; max-height: 58vh; margin-inline: auto; border-radius: var(--rad-lg); border: 1px solid var(--line); }
.media-video { width: 100%; border-radius: var(--rad-lg); border: 1px solid var(--line); }
.media figcaption { font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem; text-align: center; }

/* Terminal captures — real tool output as real text. Deliberately ink-dark in
   both themes: it reads as a terminal, and the fixed palette keeps contrast
   high (light text on near-black) regardless of the page theme. */
.term-body {
  background: #1b1e24; color: #e8e6df;
  font-family: var(--font-mono); font-size: 0.84rem; line-height: 1.6;
  padding: 1.1rem 1.3rem; margin: 0;
  border-radius: var(--rad-lg); border: 1px solid var(--line);
  overflow-x: auto;
}
.term-body:focus-visible { outline: 2px solid var(--acc); outline-offset: 2px; }
.term-prompt { color: #58c8b7; }
.term-cmd { color: #ffffff; font-weight: 600; }
/* ── TUI "waaier" — a fan of real full-screen TUI frames ──────────────────
   Base (no JS): a plain labelled stack of terminal frames, fully readable.
   The .is-fanned class (added by js/app.js) turns it into the interactive
   fan. Everything below the base block only applies when fanned. */
.media-tui { margin: 1.5rem 0; }
.tui-intro { color: var(--dim); font-size: 0.95rem; margin: 0 0 1.2rem; max-width: 70ch; }
.tui-fan { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.4rem; }
.tui-card { margin: 0; }
.tui-card-tab {
  display: flex; flex-direction: column; gap: 0.15rem; width: 100%;
  text-align: left; background: none; border: 0; padding: 0 0 0.5rem; cursor: pointer;
  color: inherit; font: inherit;
}
.tui-card-title { font-family: var(--font-serif); font-size: 1.1rem; font-weight: 700; color: var(--ink); }
.tui-card-note { color: var(--faint); font-size: 0.85rem; }
.tui-card-tab:focus-visible { outline: 2px solid var(--acc); outline-offset: 3px; border-radius: var(--rad); }
.tui-card-body { max-height: none; }

/* Fanned mode: a left-anchored deck. The screens sit staggered like a hand of
   cards — each peeks its title chip past the next — and a click brings one to
   the front (upright, readable) while the rest recede. --i is the card index
   (set inline by the builder); later cards sit higher in the stack. */
.media-tui.is-fanned .tui-fan {
  position: relative; display: block;
  height: clamp(340px, 52vh, 520px); margin: 0.6rem 0 0;
}
.media-tui.is-fanned .tui-card {
  position: absolute; top: 0; left: 0;
  width: min(600px, 84%); height: calc(100% - 44px);
  transform-origin: top left;
  transform:
    translate(calc(var(--i) * 13%), calc(var(--i) * 20px))
    rotate(calc(var(--i) * 1.3deg)) scale(0.97);
  z-index: calc(var(--i) + 1);
  transition: transform 0.28s ease, opacity 0.28s ease, filter 0.28s ease;
}
.media-tui.is-fanned .tui-card-tab {
  position: absolute; inset: 0; z-index: 2; padding: 0;
  /* the whole card is the click target in fanned mode; the chip rides on top */
}
.media-tui.is-fanned .tui-card-title {
  position: absolute; top: 0.55rem; left: 0.9rem; z-index: 3;
  background: #101216; color: #e8e6df; white-space: nowrap;
  padding: 0.18em 0.7em; border-radius: 999px; font-family: var(--font-sans);
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.01em;
}
.media-tui.is-fanned .tui-card-note { display: none; }
.media-tui.is-fanned .tui-card-body {
  margin: 0; height: 100%; overflow: hidden; pointer-events: none;
  padding-top: 2.4rem; /* a band at the top for the screen-title chip */
  box-shadow: 0 22px 50px -30px rgba(0,0,0,0.7);
}
/* A card lifts on hover/focus so you can tell it is grabbable. */
.media-tui.is-fanned .tui-card:hover,
.media-tui.is-fanned .tui-card:focus-within {
  transform:
    translate(calc(var(--i) * 13%), calc(var(--i) * 20px - 16px))
    rotate(calc(var(--i) * 1.3deg)) scale(0.99);
  z-index: 15;
}
/* When one card is front, the others recede and dim. */
.media-tui.is-fanned.has-front .tui-card:not(.is-front) { opacity: 0.45; filter: saturate(0.55); }
.media-tui.is-fanned .tui-card.is-front {
  width: min(720px, 96%);
  transform: translate(2%, 0) rotate(0deg) scale(1);
  z-index: 20;
}
.media-tui.is-fanned .tui-card.is-front .tui-card-body {
  overflow: auto; pointer-events: auto;
}
.media-tui.is-fanned .tui-card.is-front .tui-card-tab {
  /* front card: only its title chip toggles back; the body scrolls freely */
  inset: auto; width: auto;
}
.tui-hint { color: var(--faint); font-size: 0.82rem; margin: 0.9rem 0 0; text-align: center; }
.media-tui:not(.is-fanned) .tui-hint { display: none; }
@media (prefers-reduced-motion: reduce) {
  .media-tui.is-fanned .tui-card { transition: none; }
}

/* ── media "waaier" — a labelled fan of screenshots/clips (GUI vs CLI) ─────
   Reuses the TUI-fan deck (above); these rules only handle the image/video
   body. Base (no JS): a plain labelled stack. */
.media-fan .mf-label { font-family: var(--font-serif); font-size: 1.2rem; font-weight: 700; color: var(--ink); margin: 0 0 0.9rem; }
.media-fan .mf-body { padding: 0; }
.media-fan .mf-media { display: block; width: 100%; height: auto; border-radius: var(--rad-lg); border: 1px solid var(--line); background: #101216; }
.media-fan .mf-cap { display: block; font-size: 0.85rem; color: var(--faint); margin-top: 0.6rem; }
/* Fanned deck: the media fills its card (cropped from the top); caption hides. */
.media-fan.is-fanned .mf-body { padding-top: 0; }
.media-fan.is-fanned .mf-media { height: 100%; object-fit: cover; object-position: top center; border-radius: var(--rad-lg); }
.media-fan.is-fanned .mf-cap { display: none; }
/* the title chip needs a readable band over the image */
.media-fan.is-fanned .tui-card-title { top: 0.7rem; left: 0.7rem; }
/* Front card: show the whole media, uncropped, with its caption under it. */
.media-fan.is-fanned .tui-card.is-front .mf-body { overflow: hidden; display: flex; flex-direction: column; }
.media-fan.is-fanned .tui-card.is-front .mf-media { height: auto; max-height: calc(100% - 1.8rem); object-fit: contain; }
.media-fan.is-fanned .tui-card.is-front .mf-cap { display: block; }

.act-cta { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 1.5rem; }
.act-links { display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; margin-top: 1rem; }
.use-cases { color: var(--dim); font-style: italic; }

.process-page { padding: clamp(1.5rem, 4vw, 2.5rem) 0 clamp(3rem, 6vw, 5rem); }
.process-hero { padding: clamp(1.5rem, 4vw, 2.5rem) 0 clamp(2rem, 4vw, 3rem); border-bottom: 1px solid var(--line); margin-bottom: clamp(2rem, 4vw, 3rem); }
.process-hero h1 { font-size: clamp(2.2rem, 6vw, 3.6rem); margin: 0 0 1rem; }
.process-hero .lead { font-size: clamp(1.1rem, 2vw, 1.35rem); color: var(--dim); margin: 0 0 1.5rem; }
.process-intro { font-size: 1.1rem; color: var(--ink); max-width: 62ch; }
.process-body { max-width: 68ch; }
.process-sec { margin: 0 0 clamp(2rem, 4vw, 3rem); }
.process-sec h2 { font-size: clamp(1.4rem, 3vw, 1.9rem); margin: 0 0 0.8rem; }
.process-sec p { color: var(--dim); margin: 0; }
.process-cta { margin-top: clamp(2rem, 4vw, 3rem); }
