/* PrismLCA product site — one page, no dependencies, no external requests.
   Colours come from prism-theme.css (the app's tokens); the few site-only roles below are derived from
   those tokens with color-mix, so the palette stays the app's. */

/* Noto Sans 2.015 — SIL Open Font License 1.1, licence text in fonts/OFL.txt. Served from this folder,
   never from a font CDN (a CDN request transmits the visitor's IP address). One variable file covers
   every weight. */
@font-face {
  font-family: "Noto Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/NotoSansVariable.woff2") format("woff2");
}
@font-face {
  font-family: "Noto Sans";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/NotoSansVariable-Italic.woff2") format("woff2");
}

/* ------------------------------------------------------------------ site roles */
:root {
  --nav-h: 64px;
  --wrap: 1200px;
  --gutter: clamp(16px, 4vw, 32px);
  --sec-y: clamp(72px, 11vw, 150px);
  /* The prism: the app logo's conic gradient and its linear sibling for headline accents. */
  --prism-conic: conic-gradient(from var(--grad-angle, 210deg), var(--green), var(--navy), var(--purple), var(--green));
  --prism-line: linear-gradient(100deg, var(--purple), var(--violet) 30%, var(--navy) 55%, var(--green) 85%);
  --rainbow: linear-gradient(90deg, var(--violet), var(--info) 30%, var(--green) 60%, var(--wait) 82%, var(--bad));
  /* The agent stage is always dark, in both themes: a deep navy derived from the brand navy. */
  --stage: color-mix(in srgb, var(--navy) 22%, black);
  --stage-2: color-mix(in srgb, var(--navy) 34%, black);
  --stage-line: color-mix(in srgb, var(--navy) 55%, black);
  --stage-text: color-mix(in srgb, var(--navy-soft) 92%, white);
  --stage-muted: color-mix(in srgb, var(--navy-soft) 62%, var(--navy));
  --glow: color-mix(in srgb, var(--green) 45%, transparent);
  --card-shadow: 0 1px 2px color-mix(in srgb, var(--navy) 8%, transparent), 0 18px 48px -18px color-mix(in srgb, var(--navy) 35%, transparent);
  --radius: 18px;
}
/* The site is light only, whatever the visitor's system is set to: every page sets data-theme="light" on <html>
   (the light token table then outranks the dark media block of prism-theme.css, and every dark rule below is
   guarded by :root:not([data-theme="light"])) and <meta name="color-scheme" content="only light">, which also keeps
   browsers from darkening the page on their own. The dark rules stay, so a page could opt back in. */
/* The stage stays dark in the dark theme too, but there navy-soft turns dark and the two text colours above went
   dim on it. In the dark theme they come from the theme's own light text tokens, which match the light-theme
   values almost exactly. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --stage-text: color-mix(in srgb, var(--text) 92%, white); --stage-muted: var(--muted); }
}
:root[data-theme="dark"] { --stage-text: color-mix(in srgb, var(--text) 92%, white); --stage-muted: var(--muted); }
@property --grad-angle { syntax: '<angle>'; initial-value: 210deg; inherits: false; }

/* ------------------------------------------------------------------ base */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--nav-h) + 16px); -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 400 17px/1.6 "Noto Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  overflow-x: clip;
}
img { display: block; max-width: 100%; height: auto; }
a { color: var(--green-ink); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { color: var(--text); margin: 0; line-height: 1.12; letter-spacing: -0.02em; }
p { margin: 0; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.eyebrow { font-size: 0.82rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--green-ink); }
.lede { font-size: clamp(1.05rem, 1.7vw, 1.25rem); color: var(--muted); max-width: 640px; }
.grad-text { background: var(--prism-line); -webkit-background-clip: text; background-clip: text; color: transparent; }
svg.ic { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none; }

/* ------------------------------------------------------------------ buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 46px; padding: 0 22px; border-radius: 999px; border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: 0.98rem; font-weight: 600; line-height: 1; cursor: pointer;
  transition: transform .2s ease, box-shadow .2s ease, background .2s ease, border-color .2s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); border-color: var(--navy); }
.btn.primary { background: var(--green); border-color: var(--green); color: white; box-shadow: 0 8px 24px -8px var(--glow); }
.btn.primary:hover { box-shadow: 0 12px 30px -8px var(--glow); }
.btn.sm { height: 38px; padding: 0 16px; font-size: 0.9rem; }
.btn.lg { height: 54px; padding: 0 28px; font-size: 1.04rem; }
.btn.ghost { background: transparent; }
.btn.on-dark { background: transparent; color: var(--stage-text); border-color: color-mix(in srgb, white 28%, transparent); }
.btn.on-dark:hover { border-color: white; }
.btn.soon { opacity: .5; pointer-events: none; }
.btn svg.ic { width: 18px; height: 18px; }

/* ------------------------------------------------------------------ intro */
/* The end card of the tutorial videos, as an opening: the prism spins in from nothing, the wordmark drives
   in from the right, then the brand flies into its place in the nav (FLIP) while the overlay fades and the
   hero rises. html.intro-play is set by intro-gate.js before the first paint, so the overlay covers the page
   from the first frame; site.js swaps it for html.intro-out when the flight starts. It plays only on a fresh
   arrival from outside (intro-gate.js says what counts), never without JS or with reduced motion. */
.intro {
  position: fixed; inset: 0; z-index: 200; display: none;
  align-items: center; justify-content: center; background: var(--bg); transition: background .5s ease;
}
html.intro-play .intro, html.intro-out .intro { display: flex; }
html.intro-out .intro { background: transparent; }
html.intro-play, html.intro-out { overflow: hidden; }
html.intro-play .nav .brand, html.intro-out .nav .brand { visibility: hidden; }
/* The hero waits under the overlay and rises once the overlay starts to fade. */
html.intro-play .hero .reveal { opacity: 0; transform: translateY(26px); }
/* The nav brand's proportions (logo 30px, radius 8px, gap 10px, font 1.2rem) times --k, so a single FLIP
   group-scale lands pixel-true on the nav logo. Stepped rather than fluid: a unitless factor cannot come
   from vw, and rem must stay rem for the landing to fit at any browser font size. */
.intro-brand { --k: 4.4; display: flex; align-items: center; gap: calc(10px * var(--k)); will-change: transform; }
@media (max-width: 900px) { .intro-brand { --k: 3.2; } }
@media (max-width: 520px) { .intro-brand { --k: 2.2; } }
.intro-prism {
  width: calc(30px * var(--k)); height: calc(30px * var(--k)); border-radius: calc(8px * var(--k)); flex: none;
  background: var(--prism-conic); box-shadow: 0 calc(2px * var(--k)) calc(8px * var(--k)) var(--glow);
}
.intro-name { font-size: calc(1.2rem * var(--k)); font-weight: 400; letter-spacing: -0.01em; color: var(--text); }
.intro-name b { font-weight: 700; }
/* Eases as in the video: back.out(1.5) for the prism, power3.out for the wordmark. */
html.intro-play .intro-prism { animation: intro-pop .95s cubic-bezier(.34,1.45,.64,1) .1s both; }
html.intro-play .intro-name { animation: intro-drive .6s cubic-bezier(.215,.61,.355,1) .6s both; }
@keyframes intro-pop { from { transform: scale(0) rotate(-120deg); } to { transform: none; } }
@keyframes intro-drive { 0% { transform: translateX(35vw); opacity: 0; } 30% { opacity: 1; } 100% { transform: none; opacity: 1; } }

/* ------------------------------------------------------------------ nav */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50; height: var(--nav-h);
  transition: background .3s ease, box-shadow .3s ease, border-color .3s ease;
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: saturate(1.4) blur(14px); -webkit-backdrop-filter: saturate(1.4) blur(14px);
  border-bottom-color: color-mix(in srgb, var(--border) 80%, transparent);
}
.nav-inner { max-width: 1280px; margin: 0 auto; height: 100%; display: flex; align-items: center; gap: 28px; padding: 0 var(--gutter); }
/* The app's wordmark: "Prism" regular, "LCA" bold (frontend styles/base.css .brand). */
.brand { display: flex; align-items: center; gap: 10px; color: var(--text); font-weight: 400; font-size: 1.2rem; letter-spacing: -0.01em; }
.brand:hover { text-decoration: none; }
.brand b { font-weight: 700; }
.logo { width: 30px; height: 30px; border-radius: 8px; background: var(--prism-conic); box-shadow: 0 2px 8px var(--glow); flex: none; }
.nav-links { display: flex; gap: 24px; margin-left: 8px; }
.nav-links a, .nav-res a { color: var(--muted); font-weight: 560; font-size: 0.95rem; }
.nav-links a:hover, .nav-res a:hover { color: var(--text); text-decoration: none; }
.nav-res { display: flex; gap: 20px; margin-left: auto; align-items: center; }
.nav-cta { display: flex; gap: 10px; align-items: center; margin-left: auto; }
.nav-burger { display: none; margin-left: auto; width: 42px; height: 42px; border: 0; background: transparent; cursor: pointer; color: var(--text); }
.nav-burger span { display: block; width: 22px; height: 2px; margin: 5px auto; background: currentColor; border-radius: 2px; transition: transform .25s ease, opacity .25s ease; }
@media (max-width: 1040px) {
  .nav-links, .nav-res { display: none; }
  .nav-burger { display: block; margin-left: 4px; }
  .nav-cta { margin-left: auto; }
  .nav-cta .btn.ghost { display: none; }
  .nav.open { background: var(--bg); height: auto; box-shadow: var(--shadow-lg); }
  .nav.open .nav-inner { flex-wrap: wrap; padding-bottom: 18px; }
  .nav.open .nav-links, .nav.open .nav-res { display: flex; flex-direction: column; gap: 14px; width: 100%; margin: 6px 0 0; align-items: flex-start; }
  .nav.open .nav-burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav.open .nav-burger span:nth-child(2) { opacity: 0; }
  .nav.open .nav-burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
}

/* ------------------------------------------------------------------ hero */
.hero { position: relative; padding: calc(var(--nav-h) + clamp(48px, 9vw, 110px)) 0 clamp(40px, 6vw, 90px); text-align: center; overflow: clip; }
.hero-bg {
  position: absolute; inset: -10% 0 auto; height: 120%;
  background: image-set(url("img/bg-hero-light.webp") 1x, url("img/bg-hero-light@2x.webp") 2x) center top / cover no-repeat;
  will-change: transform; pointer-events: none;
}
.hero-bg::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to bottom, transparent 38%, var(--bg) 80%); }
.hero-inner { position: relative; }
.hero h1 { font-size: clamp(2.4rem, 6.4vw, 5.2rem); font-weight: 760; letter-spacing: -0.035em; margin: 18px auto 0; max-width: 20ch; text-wrap: balance; }
.hero h1 em { font-style: normal; background: var(--prism-line); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero h1 em.shine {
  background: linear-gradient(115deg, transparent 0 40%, rgba(255,255,255,.9) 50%, transparent 60% 100%), var(--prism-line);
  background-size: 250% 100%, 100% 100%; background-repeat: no-repeat; background-position: 200% 0, 0 0;
  -webkit-background-clip: text; background-clip: text; animation: shine 1.8s ease-in-out .3s 1;
}
@keyframes shine { 0% { background-position: 200% 0, 0 0; } 100% { background-position: -80% 0, 0 0; } }
/* The same light, for any rainbow word outside the start page's hero (roadmap, licences, handbook): it runs
   once when the page opens. Page rules that colour their <em> leave a .shine one alone. */
.shine {
  font-style: normal; color: transparent;
  background: linear-gradient(115deg, transparent 0 40%, rgba(255,255,255,.9) 50%, transparent 60% 100%), var(--prism-line);
  background-size: 250% 100%, 100% 100%; background-repeat: no-repeat; background-position: 200% 0, 0 0;
  -webkit-background-clip: text; background-clip: text; animation: shine 1.8s ease-in-out .3s 1;
}
/* A heading that fades in first: let it arrive before the light crosses it. */
.reveal .shine, .reveal.shine { animation-delay: .75s; }
.hero .lede { margin: 22px auto 0; text-align: center; }
.hero-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 32px; }
.hero-meta { margin-top: 16px; font-size: 0.86rem; color: var(--faint); }
.hero-meta span + span::before { content: "·"; margin: 0 9px; }
.hero-meta span { white-space: nowrap; display: inline-block; }
.pill-ai {
  display: inline-flex; align-items: center; gap: 8px; padding: 6px 14px 6px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 80%, transparent); border: 1px solid var(--border);
  font-size: 0.86rem; font-weight: 600; color: var(--text); backdrop-filter: blur(8px);
}
.pill-ai i { width: 20px; height: 20px; border-radius: 6px; background: var(--prism-conic); display: inline-block; }

/* The app window: tilted back while the hero is in view, flat once scrolled (JS sets --tilt 1 → 0). */
.stage-3d { position: relative; perspective: 1600px; margin: clamp(48px, 7vw, 84px) auto 0; max-width: 1180px; padding: 0 var(--gutter); }
.stage-3d .window { z-index: 1; }
.window {
  --tilt: 1;
  position: relative; border-radius: 16px; overflow: hidden; background: var(--surface);
  border: 1px solid var(--border); box-shadow: 0 40px 120px -40px color-mix(in srgb, var(--navy) 55%, transparent), 0 0 0 1px color-mix(in srgb, white 30%, transparent) inset;
  transform: rotateX(calc(var(--tilt) * 22deg)) scale(calc(1 - var(--tilt) * 0.08)) translateY(calc(var(--tilt) * -10px));
  transform-origin: 50% 0; will-change: transform;
}
.window-bar { display: flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.window-bar i { width: 11px; height: 11px; border-radius: 50%; background: var(--border-strong); }
.window-bar span { margin-left: 10px; font-size: 0.78rem; color: var(--faint); font-weight: 600; }
.window img, .window video { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; background: var(--surface-2); }
.hero-caption { position: relative; z-index: 2; margin: 22px auto 0; font-size: 0.86rem; color: var(--faint); max-width: 640px; padding: 0 var(--gutter); }
.glow-under { position: absolute; left: 12%; right: 12%; bottom: 6%; height: 70px; background: var(--rainbow); filter: blur(60px); opacity: .35; z-index: 0; pointer-events: none; }

/* ------------------------------------------------------------------ stats strip */
.stats { padding: clamp(56px, 8vw, 96px) 0; }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.stat { text-align: center; padding: 22px 12px; border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border); }
.stat b { display: block; font-size: clamp(2rem, 4vw, 2.9rem); font-weight: 780; letter-spacing: -0.03em; color: var(--text); font-variant-numeric: tabular-nums; }
.stat span { font-size: 0.92rem; color: var(--muted); }
@media (max-width: 760px) { .stats-grid { grid-template-columns: repeat(2, 1fr); } }

/* ------------------------------------------------------------------ section heads */
.sec { padding: var(--sec-y) 0; position: relative; }
.sec-head { max-width: 760px; margin-bottom: clamp(36px, 5vw, 64px); }
.sec-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.sec-head.center .lede { margin-left: auto; margin-right: auto; }
.sec-head h2 { font-size: clamp(2.1rem, 5vw, 3.6rem); font-weight: 760; margin: 12px 0 18px; }

/* ------------------------------------------------------------------ agent stage (always dark) */
.agent { background: var(--stage); color: var(--stage-text); overflow: clip; }
.agent h2, .agent h3 { color: white; }
.agent .lede { color: var(--stage-muted); }
.agent .eyebrow { color: var(--green); }
/* Fixed to the viewport: the section is several screens tall, and "cover" on the section itself would
   blow the 16:9 backdrop up until the facets left the frame. (iOS ignores fixed and scrolls it.) */
.agent-bg { position: absolute; inset: 0; background: image-set(url("img/bg-stage-dark.webp") 1x, url("img/bg-stage-dark@2x.webp") 2x) right center / cover no-repeat fixed; pointer-events: none; }
/* A portrait phone shows a quarter of the backdrop's width; at the right edge that is the bright knot of
   rays, behind every step's text. Short of the middle the backdrop runs dark. */
@media (max-width: 640px) { .agent-bg { background-position: 45% center; } }
.agent .wrap { position: relative; }
.story { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.25fr); gap: clamp(28px, 5vw, 72px); align-items: start; }
.story-steps { display: flex; flex-direction: column; }
.step { min-height: 72vh; display: flex; flex-direction: column; justify-content: center; padding: 28px 0; opacity: .35; transition: opacity .4s ease; }
.step.active { opacity: 1; }
.step-num { display: inline-flex; align-items: center; gap: 10px; font-size: 0.8rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--green); }
.step-num svg.ic { width: 20px; height: 20px; }
.step h3 { font-size: clamp(1.6rem, 3vw, 2.3rem); margin: 12px 0 14px; }
.step p { color: var(--stage-muted); font-size: 1.04rem; }
.step ul { margin: 16px 0 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.step li { display: flex; gap: 10px; color: var(--stage-text); font-size: 0.98rem; }
.step li svg.ic { width: 18px; height: 18px; color: var(--green); margin-top: 3px; }
.step-shot { display: none; }
.story-media { position: sticky; top: calc(var(--nav-h) + 6vh); height: 76vh; display: flex; align-items: center; }
.media-frame { position: relative; width: 100%; aspect-ratio: 4 / 3.1; }
.media-frame figure {
  position: absolute; inset: 0; margin: 0; display: flex; align-items: center; justify-content: center;
  opacity: 0; transform: translateY(24px) scale(.97); transition: opacity .6s ease, transform .7s cubic-bezier(.2,.7,.2,1);
}
.media-frame figure.on { opacity: 1; transform: none; }
.media-frame img { max-height: 100%; width: auto; max-width: 100%; border-radius: 14px; border: 1px solid var(--stage-line); box-shadow: 0 40px 100px -30px black, 0 0 0 1px color-mix(in srgb, white 6%, transparent); }
.media-frame .duo { position: relative; width: 100%; height: 100%; }
.media-frame .duo img { position: absolute; }
.media-frame .duo .a { left: 8%; top: 0; width: 52%; }
.media-frame .duo .b { right: 0; bottom: 3%; width: 82%; }
.media-frame .pages { position: relative; width: 100%; height: 100%; }
.media-frame .pages img { position: absolute; width: 38%; top: 10%; border-radius: 6px; transition: transform .8s cubic-bezier(.2,.7,.2,1); }
.media-frame .pages .p1 { left: 4%; transform: rotate(-7deg); z-index: 3; }
.media-frame .pages .p2 { left: 31%; top: 6%; transform: rotate(-1deg); z-index: 4; }
.media-frame .pages .p3 { left: 58%; transform: rotate(6deg); z-index: 3; }
.byok { margin-top: clamp(40px, 6vw, 72px); display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.byok div { padding: 20px 22px; border-radius: var(--radius); background: color-mix(in srgb, var(--stage-2) 80%, transparent); border: 1px solid var(--stage-line); }
.byok b { display: flex; align-items: center; gap: 10px; color: white; font-size: 1.02rem; margin-bottom: 6px; }
.byok b svg.ic { color: var(--green); }
.byok p { color: var(--stage-muted); font-size: 0.95rem; }
@media (max-width: 900px) {
  .story { grid-template-columns: 1fr; }
  .story-media { display: none; }
  .step { min-height: 0; opacity: 1; padding: 34px 0; }
  .step-shot { display: block; margin-top: 22px; border-radius: 12px; border: 1px solid var(--stage-line); }
  .byok { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------------ BAFU band */
.data-band { position: relative; overflow: clip; }
.data-band-bg { position: absolute; inset: -6% 0; background: image-set(url("img/bg-band-light.webp") 1x, url("img/bg-band-light@2x.webp") 2x) center / cover no-repeat; pointer-events: none; will-change: transform; }
.data-card {
  position: relative; display: grid; grid-template-columns: 1.05fr 1fr; gap: clamp(28px, 5vw, 64px); align-items: center;
  padding: clamp(32px, 5vw, 64px); border-radius: 28px; background: color-mix(in srgb, var(--surface) 82%, transparent);
  border: 1px solid var(--border); box-shadow: var(--card-shadow); backdrop-filter: blur(10px);
}
.data-card h2 { font-size: clamp(2rem, 4.4vw, 3.2rem); margin: 12px 0 16px; }
.db-graphic { position: relative; display: grid; gap: 14px; }
.db { display: flex; align-items: center; gap: 16px; padding: 18px 20px; border-radius: 16px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow); }
.db .ic-wrap { width: 46px; height: 46px; border-radius: 12px; display: grid; place-items: center; flex: none; }
.db.free .ic-wrap { background: var(--violet-soft); color: var(--violet); }
.db.own .ic-wrap { background: var(--navy-soft); color: var(--navy); }
.db b { display: block; color: var(--text); }
.db small { color: var(--muted); font-size: 0.88rem; }
.db .tag { margin-left: auto; font-size: 0.74rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; padding: 4px 10px; border-radius: 999px; }
.db.free .tag { background: var(--green-soft); color: var(--green-ink); }
.db.own .tag { background: var(--surface-3); color: var(--muted); }
.db-plus { justify-self: center; width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; background: var(--surface); border: 1px solid var(--border); color: var(--muted); font-weight: 700; }
.db-result { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-radius: 14px; background: var(--green-soft); color: var(--green-ink); font-weight: 650; }
@media (max-width: 860px) { .data-card { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------ feature carousel */
.carousel { position: relative; }
.track {
  display: grid; grid-auto-flow: column; grid-auto-columns: min(78%, 760px); gap: 22px;
  --edge: calc(max(0px, (100% - var(--wrap)) / 2) + var(--gutter));
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding: 0 var(--edge);
  padding: 8px var(--edge) 28px; scrollbar-width: none; overscroll-behavior-x: contain;
}
.track::-webkit-scrollbar { display: none; }
.slide {
  scroll-snap-align: start; border-radius: 24px; background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--card-shadow); overflow: hidden; display: flex; flex-direction: column;
  transition: transform .4s ease;
}
.slide-img { aspect-ratio: 16 / 10; background: var(--surface-2); display: flex; align-items: center; justify-content: center; overflow: hidden; border-bottom: 1px solid var(--border); }
.slide-img img { width: 100%; height: 100%; object-fit: cover; object-position: left top; transition: transform 1.2s cubic-bezier(.2,.7,.2,1); }
.slide:hover .slide-img img { transform: scale(1.03); }
.slide-img.contain img { object-fit: contain; padding: 22px; }
.slide-body { padding: 22px 26px 26px; }
.slide-body .kicker { display: inline-flex; align-items: center; gap: 8px; font-size: 0.78rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--green-ink); }
.slide-body .kicker svg.ic { width: 17px; height: 17px; }
.slide-body h3 { font-size: 1.45rem; margin: 10px 0 8px; }
.slide-body p { color: var(--muted); font-size: 0.98rem; }
.badge-ai { margin-left: 6px; padding: 2px 8px; border-radius: 999px; background: var(--purple-soft); color: var(--purple); font-size: 0.7rem; letter-spacing: .06em; }
.car-ctrl { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 0 var(--gutter); max-width: var(--wrap); margin: 6px auto 0; }
.dots { display: flex; gap: 8px; }
.dots button { width: 8px; height: 8px; border-radius: 999px; border: 0; padding: 0; background: var(--border-strong); cursor: pointer; transition: width .3s ease, background .3s ease; }
.dots button.on { width: 26px; background: var(--green); }
.arrows { display: flex; gap: 10px; }
.arrows button { width: 46px; height: 46px; border-radius: 50%; border: 1px solid var(--border-strong); background: var(--surface); color: var(--text); cursor: pointer; display: grid; place-items: center; transition: border-color .2s ease, transform .2s ease; }
.arrows button:hover { border-color: var(--navy); transform: translateY(-1px); }
.arrows button:disabled { opacity: .35; cursor: default; transform: none; }
/* Graphic slides: drawn in HTML, not screenshots */
/* Import: the prism mark with the app's import icon in the middle, the formats around it, arrows pointing in.
   The arrow SVG's viewBox is 160 × 100, the same 16:10 as .slide-img, so its units line up with the chips'
   percentages; sizes scale with the card through container units. */
.g-import { position: relative; width: 100%; height: 100%; container-type: size; }
.g-import-arrows { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.g-import-arrows line { stroke: var(--border-strong); stroke-width: .7; stroke-linecap: round; marker-end: url(#gImpHead); }
.g-import-arrows marker path { fill: var(--border-strong); }
.g-import-mark { position: absolute; left: 50%; top: 50%; width: 18cqh; aspect-ratio: 1; transform: translate(-50%, -50%);
  border-radius: 24%; display: grid; place-items: center; box-shadow: 0 10px 40px var(--glow);
  background: conic-gradient(from var(--grad-angle), var(--green), var(--navy), var(--purple), var(--green)); }
.g-import-mark svg { width: 46%; height: 46%; fill: none; stroke: #fff; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.g-import span { position: absolute; transform: translate(-50%, -50%); white-space: nowrap; padding: .7em 1em; border-radius: .8em;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow); color: var(--text);
  font-weight: 650; font-size: clamp(9px, 2cqw, 15px); }
.g-search { width: min(86%, 520px); display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.g-search .q { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-radius: 14px; background: var(--surface); border: 1px solid var(--border-strong); color: var(--text); font-weight: 600; box-shadow: var(--shadow); }
.g-search .r { display: flex; justify-content: space-between; gap: 10px; padding: 11px 16px; border-radius: 12px; background: var(--surface); border: 1px solid var(--border); font-size: 0.9rem; color: var(--text); }
.g-search .r em { font-style: normal; color: var(--faint); font-size: 0.82rem; }
.g-search .r mark { background: none; color: var(--green-ink); font-weight: 700; }
/* One line per hit: the dataset names are long, and wrapped they pushed the third hit out of the 16:10 frame. */
.g-search .r span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 640px) {
  .g-search { gap: 6px; }
  .g-search .q { padding: 9px 12px; }
  .g-search .r { padding: 7px 12px; font-size: .8rem; }
}
.g-route { width: min(90%, 560px); display: grid; gap: 16px; }
.g-route .leg { display: grid; grid-template-columns: 28px 1fr auto; align-items: center; gap: 12px; padding: 12px 16px; border-radius: 12px; background: var(--surface); border: 1px solid var(--border); font-size: 0.92rem; color: var(--text); }
.g-route .leg b { font-variant-numeric: tabular-nums; }
.g-route .leg svg.ic { color: var(--navy); }
.g-route .eol { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.g-route .eol div { border-radius: 10px; padding: 10px 12px; background: var(--surface); border: 1px solid var(--border); font-size: 0.82rem; color: var(--muted); }
.g-route .eol i { display: block; height: 6px; border-radius: 3px; margin-top: 7px; background: var(--green); }
@media (max-width: 640px) { .track { grid-auto-columns: 88%; } }

/* ------------------------------------------------------------------ control grid */
.control-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 18px; }
.tile { border-radius: 22px; background: var(--surface); border: 1px solid var(--border); padding: 26px; box-shadow: var(--shadow); position: relative; overflow: hidden; }
.tile h3 { font-size: 1.25rem; margin: 14px 0 8px; display: flex; align-items: center; gap: 10px; }
.tile p { color: var(--muted); font-size: 0.97rem; }
.tile .ic-round { width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center; background: var(--green-soft); color: var(--green-ink); }
.tile.w7 { grid-column: span 7; } .tile.w5 { grid-column: span 5; } .tile.w4 { grid-column: span 4; } .tile.w6 { grid-column: span 6; }
.audit { margin-top: 18px; display: grid; gap: 8px; }
.audit div { display: grid; grid-template-columns: 54px 1fr auto; gap: 10px; align-items: baseline; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border); font-size: 0.86rem; color: var(--text); }
.audit .who { font-size: 0.7rem; font-weight: 800; letter-spacing: .08em; color: var(--muted); }
.audit .who.ai { color: var(--purple); }
.audit button { font: inherit; font-size: 0.75rem; color: var(--green-ink); background: none; border: 0; cursor: pointer; padding: 0; }
.undo-anim { position: absolute; right: 22px; top: 22px; width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center; background: var(--surface-2); color: var(--navy); border: 1px solid var(--border); }
.undo-anim svg.ic { width: 26px; height: 26px; animation: undo-turn 3.2s ease-in-out infinite; }
@keyframes undo-turn { 0%, 60%, 100% { transform: rotate(0); } 75% { transform: rotate(-40deg); } 88% { transform: rotate(8deg); } }
.tile .shot-inset { margin-top: 18px; border-radius: 12px; border: 1px solid var(--border); }
.tile.dark { background: var(--stage); border-color: var(--stage-line); color: var(--stage-text); }
.tile.dark h3 { color: white; } .tile.dark p { color: var(--stage-muted); }
.tile.dark .ic-round { background: color-mix(in srgb, var(--green) 18%, transparent); color: var(--green); }
.no-net { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 8px; }
.no-net span { padding: 7px 12px; border-radius: 999px; border: 1px dashed color-mix(in srgb, white 25%, transparent); font-size: 0.82rem; color: var(--stage-muted); text-decoration: line-through; text-decoration-color: var(--bad); }
/* One tile over two rows: the question card needs the height for its screenshot. The screenshot sits at
   the bottom, so the card ends flush with the row beside it even when the rows run a little taller. */
.tile.tall { grid-column: span 4; grid-row: span 2; display: flex; flex-direction: column; }
.tile.tall p { margin-bottom: 18px; }
.tile.tall .shot-inset { display: block; width: 100%; height: auto; margin-top: auto; }
@media (max-width: 900px) { .tile.w7, .tile.w5, .tile.w4, .tile.w6, .tile.tall { grid-column: span 12; } .tile.tall { grid-row: auto; } }

/* ------------------------------------------------------------------ report showcase */
.report { overflow: clip; }
.report-grid { display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(28px, 5vw, 72px); align-items: center; }
.fan { position: relative; height: clamp(420px, 48vw, 600px); }
.fan img { position: absolute; width: 46%; top: 8%; border-radius: 8px; box-shadow: 0 30px 70px -24px color-mix(in srgb, var(--navy) 55%, transparent); border: 1px solid var(--border); transition: transform 1s cubic-bezier(.2,.7,.2,1); will-change: transform; }
.fan .f1 { left: 2%; z-index: 1; transform: rotate(calc(var(--spread, 0) * -9deg)) translateX(calc(var(--spread, 0) * -18px)); }
.fan .f2 { left: 20%; z-index: 2; transform: rotate(calc(var(--spread, 0) * -3deg)) translateY(calc(var(--spread, 0) * -10px)); }
.fan .f3 { left: 38%; z-index: 3; transform: rotate(calc(var(--spread, 0) * 3deg)) translateY(calc(var(--spread, 0) * -4px)); }
.fan .f4 { left: 54%; z-index: 4; top: 12%; transform: rotate(calc(var(--spread, 0) * 9deg)) translateX(calc(var(--spread, 0) * 18px)); }
.checks { margin: 26px 0 0; padding: 0; list-style: none; display: grid; gap: 14px; }
.checks li { display: grid; grid-template-columns: 28px 1fr; gap: 10px; }
.checks li svg.ic { color: var(--green-ink); margin-top: 3px; }
.checks b { color: var(--text); }
.checks span { color: var(--muted); }
@media (max-width: 900px) { .report-grid { grid-template-columns: 1fr; } .fan { order: 2; } }

/* ------------------------------------------------------------------ MCP */
.mcp-grid { display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(28px, 5vw, 64px); align-items: center; }
.term { border-radius: 18px; background: var(--stage); border: 1px solid var(--stage-line); box-shadow: 0 40px 100px -40px color-mix(in srgb, var(--navy) 70%, transparent); overflow: hidden; font: 500 0.9rem/1.65 var(--mono); color: var(--stage-text); }
.term-bar { display: flex; gap: 7px; align-items: center; padding: 12px 16px; border-bottom: 1px solid var(--stage-line); }
.term-bar i { width: 11px; height: 11px; border-radius: 50%; background: var(--stage-line); }
.term-bar span { margin-left: 10px; color: var(--stage-muted); font-size: 0.78rem; }
.term pre { margin: 0; padding: 20px 22px 24px; white-space: pre-wrap; }
.term .p { color: var(--green); }
.term .t { color: var(--stage-muted); }
.term .ok { color: var(--green); }
.term .line { opacity: 0; transform: translateY(4px); transition: opacity .35s ease, transform .35s ease; display: block; }
.term.play .line { opacity: 1; transform: none; }
.clients { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 22px; }
.clients span { padding: 8px 14px; border-radius: 999px; background: var(--surface); border: 1px solid var(--border); font-weight: 650; font-size: 0.9rem; color: var(--text); }
@media (max-width: 900px) { .mcp-grid { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------ news teaser */
.news-head { display: flex; align-items: end; justify-content: space-between; gap: 20px; margin-bottom: 28px; flex-wrap: wrap; }
.news-head h2 { font-size: clamp(1.8rem, 3.6vw, 2.6rem); margin-top: 10px; }
.news-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.news-card { display: block; border-radius: 20px; padding: 24px; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow); color: var(--text); transition: transform .25s ease, border-color .25s ease; }
.news-card:hover { text-decoration: none; transform: translateY(-3px); border-color: var(--border-strong); }
.news-card time { font-size: 0.8rem; font-weight: 700; color: var(--green-ink); letter-spacing: .06em; }
.news-card h3 { font-size: 1.15rem; margin: 10px 0 8px; }
.news-card p { color: var(--muted); font-size: 0.93rem; }
@media (max-width: 860px) { .news-grid { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------ open source */
.open-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.open-card { border-radius: 22px; padding: 28px; background: var(--surface); border: 1px solid var(--border); }
.open-card h3 { font-size: 1.2rem; margin: 14px 0 8px; }
.open-card p { color: var(--muted); font-size: 0.96rem; }
.open-card a { display: inline-flex; align-items: center; gap: 6px; margin-top: 14px; font-weight: 650; }
.open-card .ic-round { width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center; background: var(--navy-soft); color: var(--navy); }
@media (max-width: 860px) { .open-grid { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------ download */
.download { padding-bottom: calc(var(--sec-y) * .45); }
.dl-card {
  position: relative; overflow: hidden; border-radius: 32px; padding: clamp(40px, 7vw, 88px) var(--gutter);
  text-align: center; background: var(--stage); color: var(--stage-text);
}
.dl-card::before { content: ""; position: absolute; inset: 0; background: image-set(url("img/bg-stage-dark.webp") 1x, url("img/bg-stage-dark@2x.webp") 2x) center / cover no-repeat; }
.dl-card::after { content: ""; position: absolute; left: 15%; right: 15%; bottom: -60px; height: 120px; background: var(--rainbow); filter: blur(70px); opacity: .45; }
.dl-card > * { position: relative; z-index: 1; }
.dl-card h2 { color: white; font-size: clamp(2.2rem, 5vw, 3.6rem); }
.dl-card p { color: var(--stage-muted); margin: 16px auto 0; max-width: 560px; }
.dl-card .hero-cta { margin-top: 30px; }
/* "Beta", pinned to the card's corner: plain brand green with white text — the card already carries the
   prism gradient in its logo, the download buttons' rims and the glow below, a fourth one was too much. */
.dl-card .dl-beta { position: absolute; top: 22px; left: 22px; z-index: 2; padding: 6px 13px; border-radius: 999px;
  font-size: .76rem; font-weight: 750; letter-spacing: .16em; text-transform: uppercase; color: #fff;
  border: 1.5px solid var(--green); background: var(--green); cursor: default;
  box-shadow: 0 6px 24px -6px var(--glow); }
/* display: block — the logo is a <span>, and as an inline box its size and auto margins were ignored (it never showed). */
.dl-card .logo { display: block; width: 64px; height: 64px; border-radius: 18px; margin: 0 auto 22px; box-shadow: 0 10px 40px var(--glow); }

/* ------------------------------------------------------------------ tech stack */
/* One band of projects, Brightway first. The band runs only once site.js has added the seamless second copy
   (.run); otherwise the list wraps and stands still. Each logo is its SVG file used as a mask, so one file gives
   both looks: a neutral grey at rest, the brand's own colour on hover. The hex values are the brands' colours
   as Simple Icons lists them (Brightway's logo is black) — data about the logos, not theme colours. */
/* Together with the footer's own top padding, about a fifth less room than after a full section. */
.stack { padding-bottom: calc(var(--sec-y) * .72); }
/* The label above the band: the site's eyebrow between two hairlines — quieter than a section heading, so the
   download card above stays the last big statement of the page. The second half drops on a phone. */
.stack-title { display: flex; align-items: center; gap: 18px; margin: 0 0 22px; text-align: center; }
.stack-title::before, .stack-title::after { content: ""; flex: 1 1 40px; height: 1px; background: var(--border-strong); }
.stack-title .stack-why { color: var(--muted); }
@media (max-width: 520px) { .stack-title .stack-why { display: none; } }
.stack-band { display: flex; min-width: 0; overflow: hidden; }
.stack-band.run { mask-image: linear-gradient(90deg, transparent, black 7%, black 93%, transparent); }
.stack-list { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin: 0; padding: 0; list-style: none; }
.stack-band.run .stack-list { flex-wrap: nowrap; flex-shrink: 0; padding-right: 12px; animation: stack-run var(--stack-s, 60s) linear infinite; }
.stack-band.run:hover .stack-list, .stack-band.run:focus-within .stack-list { animation-play-state: paused; }
@keyframes stack-run { to { transform: translateX(-100%); } }
.stack-list a { display: flex; align-items: center; gap: 12px; padding: 12px 18px 12px 14px; border-radius: 16px;
  background: var(--surface); border: 1px solid var(--border); white-space: nowrap; color: var(--text);
  transition: border-color .2s ease; }
.stack-list a:hover, .stack-list a:focus-visible { text-decoration: none; border-color: var(--border-strong); }
.stack-list b { display: block; font-size: .93rem; font-weight: 680; line-height: 1.25; }
.stack-list small { display: block; font-size: .78rem; color: var(--muted); }
.stack-ic { flex: none; width: 26px; height: 26px; background-color: var(--muted);
  -webkit-mask: var(--m) center / contain no-repeat; mask: var(--m) center / contain no-repeat; transition: background-color .2s ease; }
.stack-list a:hover .stack-ic, .stack-list a:focus-visible .stack-ic { background-color: var(--brand); }
.stack-ic.brightway { width: 46px; height: 30px; }
.stack-ic.brightway { --m: url("stack/brightway.svg"); --brand: #000000; }
.stack-ic.python { --m: url("stack/python.svg"); --brand: #3776ab; }
.stack-ic.fastapi { --m: url("stack/fastapi.svg"); --brand: #009688; }
.stack-ic.numpy { --m: url("stack/numpy.svg"); --brand: #013243; }
.stack-ic.sqlite { --m: url("stack/sqlite.svg"); --brand: #003b57; }
.stack-ic.pytorch { --m: url("stack/pytorch.svg"); --brand: #ee4c2c; }
.stack-ic.huggingface { --m: url("stack/huggingface.svg"); --brand: #ffd21e; }
.stack-ic.typst { --m: url("stack/typst.svg"); --brand: #239dad; }
.stack-ic.electron { --m: url("stack/electron.svg"); --brand: #47848f; }
.stack-ic.react { --m: url("stack/react.svg"); --brand: #61dafb; }
.stack-ic.typescript { --m: url("stack/typescript.svg"); --brand: #3178c6; }
.stack-ic.xyflow { --m: url("stack/xyflow.svg"); --brand: #1a192b; }
.stack-ic.apacheecharts { --m: url("stack/apacheecharts.svg"); --brand: #aa344d; }
.stack-ic.d3 { --m: url("stack/d3.svg"); --brand: #f9a03c; }
.stack-ic.modelcontextprotocol { --m: url("stack/modelcontextprotocol.svg"); --brand: #000000; }
.stack-fine { margin: 22px auto 0; max-width: 640px; text-align: center; font-size: .84rem; color: var(--faint); }

/* ------------------------------------------------------------------ footer */
.footer { border-top: 1px solid var(--border); padding: 56px 0 40px; font-size: 0.93rem; }
.footer-grid { display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: 32px; }
.footer h4 { margin: 0 0 12px; font-size: 0.8rem; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }
.footer nav { display: grid; gap: 8px; }
.footer nav a { color: var(--muted); }
.footer nav a:hover { color: var(--text); }
.footer .fine { margin-top: 14px; color: var(--faint); font-size: 0.86rem; max-width: 300px; }
.footer-bottom { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: 40px; padding-top: 22px; border-top: 1px solid var(--border); color: var(--faint); font-size: 0.85rem; }
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr 1fr; } .footer-grid > :first-child { grid-column: span 2; } }

/* ------------------------------------------------------------------ reveal */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .8s ease, transform .9s cubic-bezier(.2,.7,.2,1); }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: .08s; } .reveal.d2 { transition-delay: .16s; } .reveal.d3 { transition-delay: .24s; }
html.no-js .reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .window { transform: none !important; }
  .hero h1 em.shine, .shine, .undo-anim svg.ic { animation: none; }
  .media-frame figure { transition: none; }
}

/* Undo tile: a mock of the "take back the whole turn" choice */
.undo-turn { margin-top: 20px; display: grid; gap: 8px; max-width: 360px; }
.undo-turn div { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface-2); font-size: 0.88rem; color: var(--text); }
.undo-turn div.main { background: var(--green-soft); border-color: color-mix(in srgb, var(--green) 40%, transparent); color: var(--green-ink); font-weight: 650; }
.undo-turn small { color: var(--muted); }

/* Dark system theme: the light prism backdrops give way to the app's dark one. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero-bg { background-image: image-set(url("img/bg-stage-dark.webp") 1x, url("img/bg-stage-dark@2x.webp") 2x); background-position: right top; }
  :root:not([data-theme="light"]) .data-band-bg { background-image: image-set(url("img/bg-stage-dark.webp") 1x, url("img/bg-stage-dark@2x.webp") 2x); opacity: .6; }
  :root:not([data-theme="light"]) .pill-ai { background: color-mix(in srgb, var(--surface) 70%, transparent); }
}
/* On a phone the tall hero shows only a sixth of the backdrop's width, and at the right edge that sixth is
   the bright knot where the rays meet, right behind the headline. Short of the middle the backdrop is dark
   with one faint ray left — a calm ground for the text. */
@media (prefers-color-scheme: dark) and (max-width: 640px) {
  :root:not([data-theme="light"]) .hero-bg { background-position: 45% top; }
}

/* Large screens. Above ~2000 CSS px (4K at 100 % or 5K/6K) the 3840-px backdrops are used whatever the
   pixel ratio, and the content column grows so the page does not shrink into a strip. */
@media (min-width: 2000px) {
  .hero-bg { background-image: url("img/bg-hero-light@2x.webp"); }
  .agent-bg, .dl-card::before { background-image: url("img/bg-stage-dark@2x.webp"); }
  .data-band-bg { background-image: url("img/bg-band-light@2x.webp"); }
}
@media (min-width: 2000px) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero-bg, :root:not([data-theme="light"]) .data-band-bg { background-image: url("img/bg-stage-dark@2x.webp"); }
}
@media (min-width: 2200px) {
  :root { --wrap: 1440px; }
  body { font-size: 19px; }
  .stage-3d { max-width: 1440px; }
  .nav-inner { max-width: 1560px; }
}

/* Social links: brand marks in one muted tone; on hover each mark takes its own brand colour (rules at the end). */
.footer .social a { display: inline-flex; align-items: center; gap: 9px; }
.soc-ic { width: 16px; height: 16px; flex: none; fill: currentColor; opacity: .8; }
.footer .social a:hover .soc-ic { opacity: 1; }

/* Carousel edge arrows: a transparent hot zone over each side of the track; the round arrow inside fades
   in while the pointer is in that zone. Hidden where nothing is left to scroll, and on touch screens. */
.edge-nav { position: absolute; top: 8px; bottom: 80px; width: clamp(90px, 9vw, 160px); z-index: 3; border: 0; padding: 0; background: transparent; cursor: pointer; display: none; align-items: center; }
.edge-nav.next { right: 0; justify-content: flex-end; padding-right: clamp(14px, 2vw, 32px); }
.edge-nav.prev { left: 0; justify-content: flex-start; padding-left: clamp(14px, 2vw, 32px); }
.edge-nav span { width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center; background: color-mix(in srgb, var(--surface) 92%, transparent); border: 1px solid var(--border-strong); color: var(--text); box-shadow: var(--shadow-lg); backdrop-filter: blur(6px); opacity: 0; transform: scale(.85); transition: opacity .2s ease, transform .2s ease; }
.edge-nav span svg.ic { width: 26px; height: 26px; }
.edge-nav:hover span { opacity: 1; transform: none; }
.edge-nav:hover span:hover { border-color: var(--navy); }
@media (hover: hover) and (pointer: fine) { .carousel .edge-nav.can { display: flex; } }

/* Author link in the copyright line: same colour as the line, underlined on hover only. */
.footer-bottom a.author { color: inherit; }
.footer-bottom a.author:hover { color: var(--text); }

/* Social marks in their brand colours on hover (hex values as published by Simple Icons 13.21.0). GitHub's mark
   is black, so on the dark theme it turns white, as GitHub's own guidelines allow. */
.footer .social a.soc-github:hover .soc-ic { fill: #181717; }
.footer .social a.soc-youtube:hover .soc-ic { fill: #ff0000; }
.footer .social a.soc-substack:hover .soc-ic { fill: #ff6719; }
.footer .social a.soc-linkedin:hover .soc-ic { fill: #0a66c2; }
.soc-ic { transition: fill .2s ease, opacity .2s ease; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .footer .social a.soc-github:hover .soc-ic { fill: #ffffff; }
}
:root[data-theme="dark"] .footer .social a.soc-github:hover .soc-ic { fill: #ffffff; }

/* Operating-system marks on the download buttons: filled, in the button's text colour. */
.btn svg.os-ic { width: 19px; height: 19px; flex: none; fill: currentColor; }
/* The Linux mark as a drawn outline (own drawing, no licence strings attached): the filled Tux glyph lost
   its white belly against the dark button and read as a smudge. Stroke like the other line icons. */
.btn svg.os-ic-line { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.btn svg.os-ic-line .dot { fill: currentColor; stroke: none; }

/* ------------------------------------------------------------------ consent bar (assets/consent.js)
   Not a wall: a bar at the bottom, the page stays usable. Allow and Decline share one look on purpose —
   an equal choice is part of a valid consent (DSK OH Digitale Dienste, Rn. 130 ff.). */
.consent-bar { position: fixed; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%);
  z-index: 90; width: min(760px, calc(100vw - 32px)); display: flex; align-items: center; gap: 16px 20px; flex-wrap: wrap;
  padding: 16px 20px; border-radius: 16px; background: var(--surface); color: var(--text);
  border: 1px solid var(--border); box-shadow: var(--card-shadow); }
.consent-bar p { flex: 1 1 320px; margin: 0; font-size: .92rem; line-height: 1.5; color: var(--muted); }
.consent-bar p b { color: var(--text); }
.consent-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.consent-btn { min-width: 9.5em; justify-content: center; border: 1px solid var(--border-strong, var(--border));
  background: var(--surface); color: var(--text); }
.consent-btn:hover { border-color: var(--green); }
.consent-btn[aria-pressed="true"] { border-color: var(--green); background: color-mix(in srgb, var(--green) 14%, var(--surface)); }
#privacy-settings { margin-top: 14px; padding: 16px 18px; border-radius: 14px; border: 1px solid var(--border); background: var(--surface); }
#privacy-settings p { margin: 0 0 12px; }

/* Download buttons: a prism rim like the logo's, with a soft glow of the same gradient. On hover it turns one
   and a half times and stays where it stopped — site.js runs that turn (CSS alone would snap back when the
   pointer leaves mid-turn, and a 540° turn ends on a new angle that CSS cannot carry over to the next hover).
   The gradient sits on the pseudo-elements themselves, for the same reason as .intro-prism above. The button's
   own border stays transparent: left in place, its edge showed through the rim's anti-aliased edges as a grey
   seam and made the rim look pixelated. */
.btn.ring { position: relative; border-color: transparent; }
.btn.ring:hover { border-color: transparent; }
.btn.ring::before { content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 2px; pointer-events: none;
  background: conic-gradient(from var(--grad-angle), var(--green), var(--navy), var(--purple), var(--green));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0); }
/* The glow: the same gradient blurred, kept outside the button. The mask runs after the filter, so the blur
   spreads from the button's shape and the mask then cuts the button itself out. */
.btn.ring::after { content: ""; position: absolute; inset: -18px; padding: 18px; border-radius: inherit; pointer-events: none;
  background: conic-gradient(from var(--grad-angle), var(--green), var(--navy), var(--purple), var(--green)) content-box;
  filter: blur(9px); opacity: .7;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0); }

/* Pinned carousel (site.js): the vertical scroll drives the slides sideways while the carousel stays in view.
   Only on wide screens with a fine pointer and without reduced motion; elsewhere the track scrolls as before. */
.carousel.pinned { position: sticky; }
.carousel.pinned .track { overflow-x: hidden; scroll-snap-type: none; }

/* ------------------------------------------------------------------ product tour (between agent and report)
   The product video, kept small: the player opens large anyway (assets/videos.js, videos.css). */
.tour { padding-top: clamp(40px, 6vw, 72px); padding-bottom: clamp(16px, 3vw, 32px); }
.tour-card { display: grid; grid-template-columns: minmax(0, 440px) 1fr; gap: clamp(22px, 4vw, 52px); align-items: center;
  max-width: 1040px; margin: 0 auto; padding: clamp(18px, 2.4vw, 26px); border-radius: 26px;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow); }
.tour-text h2 { font-size: clamp(1.6rem, 3vw, 2.2rem); letter-spacing: -0.025em; margin: 8px 0 10px; }
.tour-text > p:not(.eyebrow) { color: var(--muted); max-width: 46ch; }
.tour-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; margin-top: 20px; }
.tour-cta .btn svg { width: 16px; height: 16px; fill: currentColor; }
.tour-len { display: inline-flex; align-items: center; gap: 6px; font-size: 0.9rem; color: var(--muted); }
.tour-len svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
@media (max-width: 760px) { .tour-card { grid-template-columns: 1fr; } }


/* ------------------------------------------------------------------ Linux download choice (tools/build_download.py)
   A <details>: the summary looks like the other download buttons, and the two packages open as a small menu ABOVE
   the button, because the download card clips whatever overflows its bottom edge. site.js closes it again on a
   click outside or Escape. */
.dl-pick { position: relative; }
.dl-pick > summary { list-style: none; cursor: pointer; }
.dl-pick > summary::-webkit-details-marker { display: none; }
.dl-pick .dl-chev { width: 16px; height: 16px; margin-left: -2px; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; transition: transform .2s ease; }
.dl-pick[open] .dl-chev { transform: rotate(180deg); }
.dl-menu { position: absolute; z-index: 5; left: 50%; bottom: calc(100% + 12px); transform: translateX(-50%);
  width: max-content; min-width: 100%; max-width: min(340px, calc(100vw - 48px));
  display: flex; flex-direction: column; gap: 4px; padding: 8px; border-radius: 16px; text-align: left;
  background: var(--stage-2); border: 1px solid var(--stage-line);
  box-shadow: 0 18px 48px -12px color-mix(in srgb, black 60%, transparent); }
.dl-menu a { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px; border-radius: 10px; color: var(--stage-text); }
.dl-menu a:hover, .dl-menu a:focus-visible { background: color-mix(in srgb, var(--stage-text) 10%, transparent); text-decoration: none; }
.dl-menu b { font-weight: 700; }
.dl-menu a span { font-size: .84rem; color: var(--stage-muted); }
.dl-menu .dl-all { margin-top: 2px; padding-top: 10px; border-top: 1px solid var(--stage-line); border-radius: 0 0 10px 10px;
  font-size: .84rem; color: var(--stage-muted); }
