/* ==========================================================================
   D8Diffusion — design system
   Light/dark theming, driven by data-theme on <html>. Deliberately
   dependency-free: no webfonts, no CDN, no analytics. Every asset is local,
   so visiting this site sends no request to any third party. Keep it that
   way — it is itself an argument for the "runs in your own environment"
   claim.

   All copy lives in the HTML. This file is presentation only.
   ========================================================================== */

/* ------------------------------------------------------------- LIGHT ---- */
:root,
:root[data-theme="light"] {
  color-scheme: light;

  /* Brand palette (carried over from the product deck) */
  --ink:        #101c2e;   /* theme-aware dark surface: light in light mode,
                              a raised panel in dark mode */
  --ink-fixed:  #101c2e;   /* always dark, in both themes (footer, band-ink) */
  --ink-2:      #1d3050;
  --ink-soft:   #46536a;
  --teal:       #2c8c86;   /* darkened for AA contrast on light backgrounds */
  --teal-lift:  #3fb8b0;
  --teal-wash:  #eef7f6;
  --amber:      #b26f0a;   /* darkened so it is legible as text */
  --amber-lift: #f5a623;
  --amber-wash: #fdf4e6;

  /* Surfaces and text. Pages use the *-surface / *-text tokens; brand tokens
     above are fixed and shared by both themes. */
  --paper:       #faf8f4;
  --paper-2:     #f2eee6;
  --white:       #ffffff;
  --surface:     #ffffff;   /* cards, inputs */
  --raised:      #faf8f4;   /* the "raised" fill on tinted bands */
  --header-bg:   rgba(250, 248, 244, 0.9);
  --text:        #101c2e;
  --text-muted:  #46536a;   /* .muted, .lede, .dim replacements */
  --text-faint:  #6b7688;   /* captions, small meta */
  --placeholder: #9aa3b2;
  --line:        #ddd7cb;
  --line-soft:   #e9e4da;
  --line-hover:  #cfc7b8;
  --muted:       #7f8b9d;   /* footer + status-pill meta */

  /* Text and rules sitting on a permanently dark surface (footer, .band-ink) */
  --on-dark:      #f7f6f2;
  --on-dark-soft: #c3cbd8;
  --on-dark-faint:#97a2b3;
  --on-dark-line:        rgba(185, 195, 207, 0.18);
  --on-dark-line-strong: rgba(185, 195, 207, 0.25);

  /* Demo-visual palette (the placeholder figures) */
  --fig-bg:     #f2eee6;
  --fig-block:  #e4ded2;
  --fig-street: #ffffff;
  --fig-centre: #d9d2c6;
  --fig-green:  #e2ecdf;
  --fig-water:  #dfe8ee;
  --fig-label:  #46536a;
  --fig-accent: #3fb8b0;
  --fig-warn:   #f5a623;

  --font-head: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --wrap: 1120px;
  --wrap-narrow: 760px;
  --radius: 12px;
  --radius-sm: 7px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  --shadow-sm: 0 1px 2px rgba(16, 28, 46, 0.05);
  --shadow:    0 6px 24px rgba(16, 28, 46, 0.07);
  --shadow-lg: 0 18px 48px rgba(16, 28, 46, 0.1);
}

/* -------------------------------------------------------------- DARK ---- */
/* Only surfaces, text and lines change. The brand accents stay put so the
   identity is recognisable in both themes; the two light-on-dark accents
   exist precisely so the same hue works on a dark background.            */
:root[data-theme="dark"] {
  color-scheme: dark;

  --paper:       #0d1626;
  --paper-2:     #101c2e;
  --white:       #14203a;
  --surface:     #14203a;
  --raised:      #0f1b2e;
  --header-bg:   rgba(13, 22, 38, 0.9);
  --text:        #eef2f7;
  --text-muted:  #a3b0c2;
  --text-faint:  #8290a4;
  --placeholder: #6c7a90;
  --line:        #24334d;
  --line-soft:   #1b2942;
  --line-hover:  #35486a;
  --muted:       #8290a4;

  --ink-soft:    #a3b0c2;   /* .muted/.lede resolve through this too */
  --teal-wash:   #123030;
  --amber-wash:  #2f2410;

  /* a dark card must be lighter than the page for the shadows to read */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow:    0 6px 24px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 18px 48px rgba(0, 0, 0, 0.5);

  --fig-bg:     #0f1b2e;
  --fig-block:  #1b2942;
  --fig-street: #33486a;   /* clearly above the block grid so the network reads */
  --fig-centre: #3d5375;
  --fig-green:  #16302a;
  --fig-water:  #14293a;
  --fig-label:  #97a5b8;
}


/* ---------------------------------------------------------------- reset -- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, svg, video { max-width: 100%; display: block; }

a { color: var(--teal); text-decoration: none; }
a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }

h1, h2, h3, h4, .mono {
  font-family: var(--font-head);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--text);
  margin: 0;
}

h1 { font-size: clamp(1.9rem, 4.4vw, 3.05rem); }
h2 { font-size: clamp(1.45rem, 3vw, 2.05rem); }
h3 { font-size: clamp(1.02rem, 1.7vw, 1.2rem); }
h4 { font-size: 0.95rem; }

p { margin: 0 0 1.05rem; }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 1.05rem; padding-left: 1.15rem; }
li { margin-bottom: 0.5rem; }
li:last-child { margin-bottom: 0; }

strong { font-weight: 650; color: var(--text); }

::selection { background: var(--teal-lift); color: var(--text); }

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

/* Long unbroken strings (URLs, emails) must never widen the layout. */
h1, h2, h3, h4, p, li, td, th, dd, dt, a, strong, span, figcaption, label {
  overflow-wrap: break-word;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--teal);
  color: #ffffff;
  padding: 0.7rem 1.2rem;
  font-family: var(--font-head);
  font-weight: 700;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip:focus { left: 0; color: #ffffff; }

/* --------------------------------------------------------------- layout -- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 24px;
}
.wrap-narrow { max-width: var(--wrap-narrow); }

section { padding: clamp(3rem, 6.5vw, 5.4rem) 0; position: relative; }
section + section { border-top: 1px solid var(--line-soft); }

.band       { background: var(--surface); }
.band-alt   { background: var(--raised); }
.band-ink   { background: var(--ink-fixed); color: var(--on-dark); }
.band-ink h2, .band-ink h3, .band-ink h4 { color: var(--on-dark); }
.band-ink a { color: var(--teal-lift); }
.band-ink a:hover { color: #ffffff; }

/* keep anchor targets clear of the sticky header */
[id] { scroll-margin-top: 92px; }

/* --------------------------------------------------------------- header -- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--header-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.site-header.is-stuck {
  border-bottom-color: var(--line);
  box-shadow: var(--shadow-sm);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  min-height: 70px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-head);
  font-weight: 700;
  /* The product name is a proper noun phrase now, not a short token, so it is
     a touch smaller than a coined name would be. It still has to hold one line
     next to the navigation. */
  font-size: clamp(0.86rem, 1.35vw, 1.02rem);
  letter-spacing: -0.02em;
  line-height: 1.12;
  color: var(--text);
  min-width: 0;
}
.brand:hover { text-decoration: none; color: var(--text); }
.brand-text { display: block; min-width: 0; }

/* ---- day / night mark -------------------------------------------------
   Two <img> elements, one per theme, swapped on [data-theme]. Deliberately
   not a <picture> media query: that follows the OS colour scheme, while
   data-theme follows this site's own toggle, and the two can disagree. */
.brand-marks {
  display: block;
  flex: none;
  width: 26px;
  height: 30px;
  position: relative;
}
.brand-marks picture { display: block; }

/* The artwork is a raster image (an inline SVG could not carry this detail at
   30px), so it needs an explicit box. width/height in the markup reserve the
   space and prevent layout shift; object-fit keeps it undistorted. */
.brand-mark {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Show exactly one mark. The selectors are deliberately two classes deep so
   they outrank any generic `.brand-marks img` display rule — with a single
   class they would lose, and both marks would render on top of each other. */
.brand-marks .mark-day   { display: block; }
.brand-marks .mark-night { display: none; }
:root[data-theme="dark"] .brand-marks .mark-day   { display: none; }
:root[data-theme="dark"] .brand-marks .mark-night { display: block; }

.brand-sub {
  display: block;
  font-size: 0.58rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  line-height: 1;
  margin-top: 3px;
}

.nav-right { display: flex; align-items: center; gap: 1.6rem; }

.nav-links {
  display: flex;
  align-items: center;
  gap: 1.7rem;
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 0 0 auto;
}
.nav-links > li { flex: 0 0 auto; margin: 0; }
.nav-links a {
  display: inline-block;
  font-family: var(--font-head);
  font-size: 0.79rem;
  font-weight: 500;
  color: var(--text-muted);
  padding: 0.4rem 0;
  position: relative;
  white-space: nowrap;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background: var(--teal);
  transition: width 0.25s var(--ease);
}
.nav-links a:hover { color: var(--text); text-decoration: none; }
.nav-links a:hover::after { width: 100%; }
.nav-links a[aria-current="page"] { color: var(--text); }
.nav-links a[aria-current="page"]::after { width: 100%; }

/* language switch */
.lang-switch {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 2px;
  background: var(--surface);
  flex: 0 0 auto;
}
.lang-switch a {
  font-family: var(--font-head);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 0.3rem 0.62rem;
  border-radius: 100px;
  color: var(--text-muted);
  line-height: 1.5;
}
.lang-switch a:hover { color: var(--text); text-decoration: none; }
.lang-switch a[aria-current="true"] { background: var(--teal); color: #ffffff; }
.lang-switch a[aria-current="true"]:hover { color: #ffffff; }

/* mobile menu */
.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  width: 42px;
  height: 38px;
  cursor: pointer;
  padding: 0;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.nav-toggle span {
  display: block;
  width: 18px;
  height: 2px;
  background: var(--ink);
  position: relative;
  transition: background 0.2s var(--ease);
}
.nav-toggle span::before, .nav-toggle span::after {
  content: "";
  position: absolute;
  left: 0;
  width: 18px;
  height: 2px;
  background: var(--ink);
  transition: transform 0.25s var(--ease), top 0.25s var(--ease);
}
.nav-toggle span::before { top: -6px; }
.nav-toggle span::after  { top: 6px; }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after  { top: 0; transform: rotate(-45deg); }

/* Breakpoint raised from 900px: the product name is now a long noun phrase
   ("Digital Twin Simulation"), so the desktop header needs more room before the
   navigation and CTA can sit on one line with it. */
@media (max-width: 1000px) {
  .nav-toggle { display: inline-flex; }
  .nav-right {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow);
    padding: 0.4rem 24px 1.15rem;
    display: none;
  }
  .nav-right.is-open { display: flex; }
  .nav-links { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-links li { border-bottom: 1px solid var(--line-soft); }
  .nav-links li:last-child { border-bottom: 0; }
  .nav-links a { display: block; padding: 0.9rem 0; font-size: 0.9rem; }
  .nav-links a::after { display: none; }
  .nav-right .lang-switch { margin-top: 1rem; align-self: flex-start; }
  .nav-right .btn { margin-top: 0.85rem; }

  /* the theme toggle sits inline with the language switch on mobile, then the
     CTA goes full width below */
  .nav-right .theme-toggle { margin-top: 1rem; }
}

/* ------------------------------------------------------- theme toggle ---- */
.theme-toggle {
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text-muted);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease),
              background 0.2s var(--ease);
}
.theme-toggle:hover { color: var(--teal); border-color: var(--teal); }
.theme-toggle svg { width: 17px; height: 17px; display: block; }
.theme-toggle .icon-sun,
.theme-toggle .icon-moon { display: none; }

/* show the icon for the theme you would switch TO */
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }
:root[data-theme="dark"]  .theme-toggle .icon-sun  { display: block; }

/* if CSS fails to load, both icons stay hidden rather than both showing */
@media (prefers-reduced-motion: reduce) {
  .theme-toggle { transition: none; }
}

/* ---------------------------------------------------------------- hero --- */
/* Text and the detailed mark side by side. The mark is decorative, so it
   yields to the copy on narrow screens rather than pushing it down the page. */
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
  gap: clamp(1.6rem, 4vw, 3.4rem);
  align-items: center;
}
.hero-copy { min-width: 0; }

.hero-figure {
  min-width: 0;
  display: flex;
  justify-content: center;
}
.hero-figure picture { display: block; }
.hero-figure img {
  width: 100%;
  max-width: 380px;
  height: auto;
  /* a soft contact shadow so the artwork sits on the page rather than floating */
  filter: drop-shadow(0 18px 32px rgba(16, 28, 46, 0.18));
}
:root[data-theme="dark"] .hero-figure img {
  filter: drop-shadow(0 18px 32px rgba(0, 0, 0, 0.55));
}

/* Day / night hero art, swapped on [data-theme] like the header marks.
   Two classes deep for the same reason: a bare single-class rule would lose to
   any element-level display rule and both pictures would show at once. */
.hero-figure .hero-mark-day   { display: block; }
.hero-figure .hero-mark-night { display: none; }
:root[data-theme="dark"] .hero-figure .hero-mark-day   { display: none; }
:root[data-theme="dark"] .hero-figure .hero-mark-night { display: block; }

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-figure { order: -1; }
  .hero-figure img { max-width: 230px; }
}
@media (max-width: 560px) {
  .hero-figure img { max-width: 170px; }
}

/* -------------------------------------------------------------- buttons -- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: var(--font-head);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 0.72rem 1.3rem;
  border-radius: 100px;
  border: 1px solid transparent;
  cursor: pointer;
  flex: 0 0 auto;
  white-space: nowrap;
  transition: background 0.2s var(--ease), color 0.2s var(--ease),
              border-color 0.2s var(--ease), transform 0.2s var(--ease),
              box-shadow 0.2s var(--ease);
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }

.btn-primary { background: var(--ink); color: var(--on-dark); }
.btn-primary:hover { background: var(--teal); color: #ffffff; box-shadow: var(--shadow); }

.btn-accent { background: var(--teal); color: #ffffff; }
.btn-accent:hover { background: var(--ink); color: var(--on-dark); box-shadow: var(--shadow); }

.btn-ghost { background: transparent; color: var(--text); border-color: var(--line); }
.btn-ghost:hover { border-color: var(--text); color: var(--text); }

.btn-lg { padding: 0.92rem 1.7rem; font-size: 0.87rem; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.7rem; margin-top: 1.9rem; }

/* ------------------------------------------------------------- typography -- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-head);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 1.15rem;
}
.eyebrow::before { content: ""; width: 22px; height: 2px; background: var(--teal); }

.lede { font-size: clamp(1.02rem, 1.7vw, 1.16rem); color: var(--text-muted); max-width: 62ch; }
.band-ink .lede { color: var(--on-dark-soft); }

.muted { color: var(--text-muted); }
.small { font-size: 0.88rem; }
.tiny  { font-size: 0.78rem; line-height: 1.62; }

.section-head { max-width: 64ch; margin-bottom: clamp(1.8rem, 3.6vw, 2.8rem); }
.section-head h2 { margin-bottom: 0.85rem; }
.section-head .eyebrow { margin-bottom: 0.95rem; }

/* ---------------------------------------------------------------- grids -- */
.grid { display: grid; gap: 1.05rem; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 880px) { .grid-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------- cards -- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.45rem 1.4rem;
  transition: border-color 0.25s var(--ease), box-shadow 0.25s var(--ease),
              transform 0.25s var(--ease);
}
.band-alt .card { background: var(--surface); }
.card:hover { border-color: var(--line-hover); box-shadow: var(--shadow); transform: translateY(-2px); }
.card h3 { margin-bottom: 0.5rem; }
.card p { color: var(--text-muted); font-size: 0.94rem; }
.card > :last-child { margin-bottom: 0; }

.card-num {
  font-family: var(--font-head);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  color: var(--teal);
  display: block;
  margin-bottom: 0.85rem;
}

/* ---------------------------------------------------------------- steps -- */
.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
.steps > li {
  position: relative;
  padding: 1.35rem 0 1.35rem 3.5rem;
  border-top: 1px solid var(--line-soft);
  margin: 0;
}
.steps > li:last-child { border-bottom: 1px solid var(--line-soft); }
.steps > li::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 1.3rem;
  font-family: var(--font-head);
  font-size: 0.82rem;
  font-weight: 700;
  color: #ffffff;
  background: var(--teal);
  /* A hexagon, matching the honeycomb and the nodes. clip-path discards the
     border, so the pale wash plus hairline outline becomes a solid fill — the
     same treatment as the tick, which keeps the two consistent. */
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
  width: 2.3rem;
  height: 2.3rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.steps > li h3 { margin-bottom: 0.35rem; font-size: 1.05rem; }
.steps > li p { color: var(--text-muted); font-size: 0.95rem; margin-bottom: 0; }

/* Two labels joined by a directional edge.
   The pair reads as one statement: the left label is the input, the right the
   result, and the arrow between them is drawn as a line with a CSS triangle
   instead of typed as —, which sat between two loose blocks and read as three
   unrelated things. Neither label carries a box or a background: at this width
   any container competed with the words, and the words carry it on their own. */
.edge-pair {
  display: grid;
  grid-template-columns: auto auto auto;
  justify-content: start;
  align-items: center;
  gap: 0 0.6rem;
  margin-top: 0.7rem;
  font-size: 0.85rem;
}
/* Pill shells, the same radius as the buttons, but nothing else borrowed from
   them: no fill, no weight change, no cursor, no hover. An outline capsule reads
   as a container; a filled one would read as something to press. */
.edge-node {
  min-width: 0;
  padding: 0.42rem 1.05rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  color: var(--text-muted);
}
/* The target side carries the conclusion, so its text reads a shade stronger.
   Its border stays neutral on purpose: a coloured outline capsule is exactly what
   .btn-ghost looks like, and these are not buttons. The teal lives on the arrow. */
.edge-node--out { color: var(--text); }
.edge-node-label { display: block; }
.edge-link {
  position: relative;
  width: 2.2rem;
  height: 2px;
  background: var(--teal);
}
.edge-link::after {
  content: "";
  position: absolute;
  right: -1px;
  top: 50%;
  transform: translateY(-50%);
  width: 0;
  height: 0;
  border-left: 8px solid var(--teal);
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
}

@media (max-width: 620px) {
  /* Below this width the pair stands upright: the same statement, read
     downwards, rather than two columns squeezed to a few characters each. */
  .edge-pair {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }
  .edge-node {
    justify-self: start;
    max-width: 100%;
  }
  .edge-link {
    width: 2px;
    height: 1.6rem;
    justify-self: start;
    margin: 0.4rem 0 0.4rem 0.55rem;
  }
  .edge-link::after {
    right: auto;
    left: 50%;
    top: auto;
    bottom: -1px;
    transform: translateX(-50%);
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 8px solid var(--teal);
    border-bottom: 0;
  }
}

/* --------------------------------------------------------------- figure -- */
/* Wraps demo media. Replace the inner .figure-media contents with a real
   screenshot/GIF/video — see README for what is expected here.            */
.figure {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
}
.figure-media {
  position: relative;
  background: var(--raised);
  border-bottom: 1px solid var(--line);
}
.figure-media svg { width: 100%; height: auto; display: block; }

/* ---------------------------------------------------------------------------
   Placeholder figure styling.
   The demo SVGs use classes rather than hardcoded fills so they follow the
   theme like everything else. When you swap in a real capture, these rules can
   go with the placeholder markup.
   --------------------------------------------------------------------------- */
.fig-bg     { fill: var(--fig-bg); }
.fig-block  { stroke: var(--fig-block); }
.fig-street { stroke: var(--fig-street); }
.fig-centre { stroke: var(--fig-centre); }
.fig-green  { fill: var(--fig-green); }
.fig-water  { fill: var(--fig-water); }
.fig-label  { fill: var(--fig-label); }
.fig-accent { fill: var(--fig-accent); }
.fig-warn   { fill: var(--fig-warn); }
.fig-orbit  { stroke: var(--fig-accent); }
.fig-grid   { stroke: var(--fig-block); }
.fig-stroke-accent { stroke: var(--fig-accent); }
.figure-badge {
  position: absolute;
  top: 0.8rem;
  left: 0.8rem;
  font-family: var(--font-head);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  background: var(--amber-wash);
  color: var(--amber);
  border: 1px solid rgba(178, 111, 10, 0.3);
  border-radius: 100px;
  padding: 0.28rem 0.62rem;
}
.figure figcaption {
  padding: 1rem 1.25rem;
  font-size: 0.88rem;
  color: var(--text-muted);
  background: var(--surface);
}
.figure figcaption strong { color: var(--text); }

/* --------------------------------------------------------------- callout -- */
.callout {
  border-left: 3px solid var(--teal);
  padding: 0.15rem 0 0.15rem 1.3rem;
  margin: 1.8rem 0 0;
}
.callout p { font-size: 1.02rem; }
.band-ink .callout { border-left-color: var(--teal-lift); }

.note {
  background: var(--teal-wash);
  border: 1px solid rgba(44, 140, 134, 0.2);
  border-radius: var(--radius-sm);
  padding: 1.05rem 1.15rem;
  font-size: 0.87rem;
  color: var(--text-muted);
}
.note strong { color: var(--text); }
.note-amber {
  background: var(--amber-wash);
  border-color: rgba(178, 111, 10, 0.24);
}

/* ------------------------------------------------------------ pillar box -- */
.pillar { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.05rem; }
@media (max-width: 720px) { .pillar { grid-template-columns: 1fr; } }
.pillar > div {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.5rem 1.45rem;
}
.band-alt .pillar > div { background: var(--surface); }
.pillar h3 {
  font-size: 0.74rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 0.8rem;
}
.pillar p { color: var(--text-muted); font-size: 0.95rem; }
.pillar ul { color: var(--text-muted); font-size: 0.95rem; }

/* ---------------------------------------------------------------- facts -- */
.facts { list-style: none; margin: 0; padding: 0; }
.facts > li {
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: 1rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--line-soft);
  margin: 0;
}
.facts > li:first-child { border-top: 1px solid var(--line-soft); }
.facts .tick {
 width: 1.4rem;
 height: 1.4rem;
 
 background: var(--teal);
 color: #ffffff;
 display: flex;
 align-items: center;
 justify-content: center;
 font-size: 0.7rem;
 font-weight: 700;
 margin-top: 0.2rem; clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }
.facts strong { display: block; font-family: var(--font-head); font-size: 0.95rem; margin-bottom: 0.2rem; }
.facts p { color: var(--text-muted); font-size: 0.92rem; margin: 0; }

/* --------------------------------------------------------------- status -- */
.status-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.8rem;
  margin-bottom: 1.3rem;
}
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-family: var(--font-head);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.34rem 0.75rem;
  border-radius: 100px;
  border: 1px solid;
}
.status-pill::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.status-pill.works  { color: var(--teal); border-color: rgba(44,140,134,.3); background: var(--teal-wash); }
.status-pill.later  { color: var(--amber); border-color: rgba(178,111,10,.3); background: var(--amber-wash); }
.status-pill.soon   { color: var(--text-muted); border-color: var(--line); background: transparent; }

.status-list { list-style: none; margin: 0 0 1.5rem; padding: 0; }
.status-list li {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  padding: 0.62rem 0;
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.94rem;
  margin: 0;
}
.status-list li:last-child { border-bottom: 0; }
.status-list .mark { font-weight: 700; flex: none; width: 1rem; font-family: var(--font-head); }
.status-list .yes .mark { color: var(--teal); }
.status-list .no  .mark { color: var(--amber); }
.status-list .no { color: var(--text-muted); }

/* --------------------------------------------------------------- offer -- */
.offer { display: grid; grid-template-columns: 1fr 1fr; gap: 1.05rem; }
@media (max-width: 720px) { .offer { grid-template-columns: 1fr; } }
.offer > div {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.45rem 1.4rem;
  background: var(--surface);
}
.offer h3 {
  font-size: 0.74rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  margin-bottom: 0.85rem;
}
.offer-you h3 { color: var(--text); }
.offer-them h3 { color: var(--teal); }
.offer ul { margin: 0; padding-left: 1.1rem; font-size: 0.94rem; color: var(--text-muted); }

/* -------------------------------------------------------- preview gate ----
   TEMPORARY. Belongs to the password gate in _build/build.py; when that is
   disabled none of this markup is emitted and these rules simply match nothing.
   Left in place so the removal is one edit in one file, not a hunt.

   Fail closed: `.site-gate` is visible unless <html data-gate="open">, and while
   locked every other top-level element in <body> is hidden. With JavaScript off
   the gate still covers the screen, which is the safer default for "not public
   yet". */
.site-gate {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background: var(--ink-fixed);
  color: var(--on-dark);
}
html[data-gate="open"] .site-gate { display: none; }
html[data-gate="locked"] body > *:not(.site-gate) { display: none !important; }

.site-gate__box {
  width: min(100%, 23rem);
  display: grid;
  gap: 0.7rem;
}
.site-gate__brand {
  font-size: 0.66rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--on-dark-faint);
  margin: 0;
}
.site-gate h1 {
  font-size: 1.35rem;
  margin: 0;
  color: var(--on-dark);
}
.site-gate__lede {
  margin: 0;
  font-size: 0.9rem;
  color: var(--on-dark-soft);
}
.site-gate label {
  font-size: 0.78rem;
  color: var(--on-dark-faint);
  margin-top: 0.35rem;
}
.site-gate input {
  width: 100%;
  padding: 0.7rem 0.8rem;
  font: inherit;
  font-size: 0.95rem;
  color: var(--on-dark);
  background: rgba(185, 195, 207, 0.1);
  border: 1px solid var(--on-dark-line-strong);
  border-radius: 6px;
}
.site-gate input:focus-visible {
  outline: 2px solid var(--teal-lift);
  outline-offset: 2px;
}
.site-gate .btn {
  justify-self: start;
  margin-top: 0.5rem;
}
.site-gate__err {
  margin: 0;
  font-size: 0.82rem;
  color: #f0a3a3;
}
.site-gate__note {
  margin: 0.6rem 0 0;
  font-size: 0.72rem;
  color: var(--on-dark-faint);
}

/* -------------------------------------------------------------- footer -- */
.site-footer {
  background: var(--ink-fixed);
  color: var(--on-dark-soft);
  padding: clamp(2.4rem, 5vw, 3.4rem) 0 1.8rem;
  font-size: 0.88rem;
}
.site-footer h4 {
  font-size: 0.66rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--on-dark-faint);
  margin-bottom: 0.9rem;
}
.footer-top {
  display: grid;
  /* Four hugging tracks, with the leftover split evenly by space-between.
     Widths: the brand block sizes to its own content; the three link columns are
     held at a shared 156px below, which makes them exactly equal rather than the
     95 / 154 / 106px their text alone would give. space-between then divides
     whatever remains equally across every gap, so the gap before "This page"
     matches the gaps between the columns — that equality is what reads as
     symmetrical, and it is guaranteed here rather than happening by luck.

     minmax(0, auto), not bare auto: a plain auto track refuses to shrink below
     its content, so if the columns ever add up to more than the wrap the grid
     would overflow — and with body { overflow-x: hidden } that would be clipped
     silently instead of scrolling. */
  grid-template-columns: repeat(4, minmax(0, auto));
  justify-content: space-between;
  gap: 2rem;
  padding-bottom: 2.2rem;
  border-bottom: 1px solid var(--on-dark-line);
}
@media (max-width: 900px) { .footer-top { grid-template-columns: 1fr 1fr; } }
@media (max-width: 540px) { .footer-top { grid-template-columns: 1fr; gap: 1.7rem; } }

/* The footer stays dark in BOTH themes, so its brand text must use the
   on-dark tokens. var(--paper) would be near-black in dark mode and vanish
   against the footer background. */
.footer-brand .brand { color: var(--on-dark); }
.footer-brand .brand:hover { color: #ffffff; }
/* no edge shadow needed against a dark footer */
.footer-brand .brand-mark { filter: none; }
.footer-brand .brand-sub { color: var(--on-dark-faint); }
.footer-brand p { color: var(--on-dark-faint); font-size: 0.84rem; max-width: 36ch; margin-top: 0.9rem; }

/* Tagline and honeycomb share one row: the hexagons sit to the right of the
   tagline, still under the brand lockup.

   `flex-wrap` is what makes this responsive without a breakpoint. The paragraph
   asks for a minimum of 18ch and grows to 32ch; the honeycomb is fixed at its
   own size. When the footer column is too narrow to hold both, the honeycomb
   wraps onto its own line below the tagline instead of crushing the text into a
   sliver — which matters here because the footer column is only 1.7fr of a
   four-column grid, roughly 400px on a desktop and narrower at the 900px
   breakpoint. */
.footer-brand .footer-brand-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* row-gap 1.6rem, not 1.1rem: when this row wraps on a narrow screen the
     honeycomb drops below the tagline, and its 14.72px lift would eat almost all
     of a 17.6px row gap (leaving ~2.9px). 25.6px keeps the same ~11px clearance
     as the desktop layout. */
  gap: 1.6rem 1.25rem;
  /* 0.9rem was enough before the honeycomb was lifted; with a 14.72px rise it
     would have closed the whole gap to the brand lockup above (leaving ~0.05px).
     1.6rem keeps ~11px of clearance. */
  margin-top: 1.6rem;
}
/* 20ch basis: the row goes side-by-side once the column is wide enough to give
   the tagline ~20ch, and stacks below that. Measured: the brand column is 353px
   on a desktop (1.7fr of a 1120px wrap), the honeycomb alone is 129px, so the
   tagline gets ~204px — about four lines. A 32ch cap was tried first and did
   not fit, which pushed the honeycomb onto its own line at exactly the size the
   side-by-side layout was meant for. */
.footer-brand .footer-brand-row p {
  /* No flex-grow, and a 24ch cap. This is what creates the separation: if the
     paragraph grows, it fills the column and shoves the honeycomb hard against
     the column edge, so the only gap to the next column is the grid gap. Capped
     and shrinkable, the tagline takes 24ch and the leftover column width becomes
     empty space to the right of the honeycomb — which is exactly the gap the eye
     needs between the hexagons and the link columns. */
  flex: 0 1 24ch;
  max-width: 24ch;
  margin-top: 0;
}
/* The honeycomb is 129px wide and its east-most vertices sit exactly on the
   box edge, so without this it butts straight up against the column edge and the
   only separation from the next footer column is the 2rem grid gap. The
   margin-right buys extra air on the right only; the tagline absorbs it (204px
   -> 188px, still four lines). */
.footer-brand .footer-brand-row .socials {
  flex: 0 0 auto;
  margin-top: 0;
  /* no margin-right: the brand track now hugs its content, so the grid gap
     alone is the separation. A margin here would make that one gap 16px wider
     than every other gap and reintroduce the asymmetry. */
}


.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin-bottom: 0.55rem; }
.footer-col a { color: var(--on-dark-soft); font-size: 0.85rem; }
.footer-col a:hover { color: var(--teal-lift); }

/* All three link columns share one width, measured rather than assumed. Their
   widest lines are 95px ("This page"), 154px (Contact — the long email address)
   and 106px (Legal): a 59px spread, which is why they looked unequal. Pinning
   them to the widest (156px) makes them exactly equal, and it also pulls Legal
   in from the right edge as a side effect — its text is 106px, so it now ends
   50px short of the edge instead of sitting flush against it.

   min-inline-size on the items, not a fixed track width: at 901px the four
   columns plus gaps need 845px and the wrap offers 853px, so it still fits, and
   at 900px the grid switches to two columns anyway. */
.footer-top > .footer-col {
  min-inline-size: 9.75rem;
}

/* social buttons */
/* --------------------------------------------------------- social hexagon --
   Seven social links as a honeycomb: one hub in the middle, six cells around it.
   Hexagonal cells, not circles — circles read as a ring, hexagons read as the
   brand mark. The row version is preserved in website2.0.row-layout/.

   Cell geometry. Flat-top hexagons (horizontal top and bottom edges) tile in
   exactly the pattern we want: neighbours directly above and below, plus four
   diagonals, and none directly left or right.

       width  W = 34px,  height H = 0.866 * W = 29.44px   (H/W = sqrt3/2)
       clip-path puts the vertices at 25%/75% along the top and bottom, which
       makes all six edges equal only when H/W = sqrt3/2. Keep the 29.44: round
       it and the shape stops being regular and the gaps go uneven.

   Size is ONE decision. The whole cluster derives from W, so resizing means
   scaling every number by the same factor:
       H = 0.866 W    dx = 0.784 W    dy = 0.452 W    vertical = 0.906 W
       box = 2.568 W wide, 2.678 W tall

   W = 34 was chosen so the cluster height matches the tagline beside it, which
   was measured rather than guessed: Segoe UI at 0.84rem/1.68 wrapped at the
   24ch cap gives 4 lines in BOTH languages, so 4 * 22.58 = 90.3px. The box here
   is 87 x 91 — within a pixel of that. (An earlier 50px cell made a 134px box,
   which is why it towered over the text.)

   Cells are 34 x 29.4, still above the 24px minimum target size. Offsets are
   perfect-tiling values times ~1.054, keeping a ~1.4px gap — the same
   proportion as at every earlier size, since all numbers scale together.

   Two consequences of clip-path worth knowing:
     * a CSS `border` gets clipped away, so cells are drawn with a translucent
       fill instead of a stroke;
     * an `outline` is clipped too, so keyboard focus uses a drop-shadow glow,
       which follows the clipped shape rather than the box. */
.socials {
  position: relative;
  width: 87px;
  height: 91px;
  margin-top: 1.15rem;
  /* Nudged up by half a cell height: H/2 = 29.44 / 2 = 14.72px. The cells are
     absolutely positioned inside this box, so one translate lifts the whole
     honeycomb without touching any of the seven offsets. A transform rather than
     a margin so the lift does not change the box's layout height — the row stays
     centred on the tagline, the cluster just sits higher within it. */
  transform: translateY(-14.72px);
}
.socials a {
  position: absolute;
  left: 50%;
  top: 50%;
  --dx: 0px;
  --dy: 0px;
  width: 34px;
  height: 29.44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--on-dark-soft);
  background: var(--on-dark-line);
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
  transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy)));
  transition: background 0.2s var(--ease), color 0.2s var(--ease),
              transform 0.2s var(--ease);
}
.socials a:hover,
.socials a:focus-visible {
  background: var(--teal);
  /* --on-dark, not --white: --white is redefined per theme and the footer is
     always dark, so the icon needs the theme-independent light token */
  color: var(--on-dark);
  transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy) - 3px));
  text-decoration: none;
  /* cells sit ~2px apart, so lifting one must also bring it to the front —
     otherwise the teal cell would slide under its neighbour */
  z-index: 2;
}
.socials a:focus-visible {
  filter: drop-shadow(0 0 5px var(--teal));
}
.socials svg { width: 12px; height: 12px; display: block; }

/* honeycomb positions */
.socials .pos-top    { --dx:   0px;   --dy: -30.8px; }
.socials .pos-ur     { --dx:  26.7px; --dy: -15.4px; }
.socials .pos-lr     { --dx:  26.7px; --dy:  15.4px; }
.socials .pos-bottom { --dx:   0px;   --dy:  30.8px; }
.socials .pos-ll     { --dx: -26.7px; --dy:  15.4px; }
.socials .pos-ul     { --dx: -26.7px; --dy: -15.4px; }

/* the hub: a touch brighter so the centre reads as the centre */
.socials .pos-center {
  --dx: 0px;
  --dy: 0px;
  background: var(--on-dark-line-strong);
  color: var(--on-dark);
}


.footer-details {
  margin: 0;
  padding-top: 0.9rem;
  font-size: 0.74rem;
  line-height: 1.8;
  color: var(--on-dark-faint);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  justify-content: space-between;
  align-items: center;
  padding-top: 1.5rem;
  font-size: 0.78rem;
  color: var(--on-dark-faint);
}
.footer-bottom p { margin: 0; }
.footer-legal { display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem; }
.footer-legal a { color: var(--on-dark-faint); }
.footer-legal a:hover { color: var(--teal-lift); }

/* ---------------------------------------------------------- legal pages -- */
.page-hero {
  padding: clamp(2.6rem, 5.5vw, 4rem) 0 clamp(1.6rem, 3.5vw, 2.4rem);
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface);
}
.page-hero h1 { font-size: clamp(1.6rem, 3.6vw, 2.3rem); }
.page-hero .lede { margin-top: 1rem; }

.prose h2 { margin-top: 2.6rem; margin-bottom: 0.8rem; font-size: 1.22rem; }
.prose h3 { margin-top: 1.8rem; margin-bottom: 0.6rem; font-size: 1rem; }
.prose p, .prose li { color: var(--text-muted); }
.prose > :first-child { margin-top: 0; }
.prose ul { padding-left: 1.2rem; }

/* ------------------------------------------------------------ utilities -- */
.center { text-align: center; }
.center .lede, .center .section-head { margin-inline: auto; }
.center .btn-row { justify-content: center; }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 1rem; }
.mt-2 { margin-top: 1.8rem; }
.mt-3 { margin-top: 2.6rem; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------- motion -- */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
}
.reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .card, .btn, .socials a { transition: none; }
  .btn:hover, .card:hover, .socials a:hover { transform: none; }
}

/* ---------------------------------------------------------------- print -- */
@media print {
  .site-header, .site-footer, .skip, .btn, .socials, .theme-toggle { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .reveal { opacity: 1 !important; transform: none !important; }

  /* force the placeholder figures back to their light palette, so a reader
     who prefers dark mode does not print a page of dark blocks */
  .fig-bg     { fill: #ffffff !important; }
  .fig-block  { stroke: #dddddd !important; }
  .fig-street { stroke: #f4f4f4 !important; }
  .fig-centre { stroke: #cccccc !important; }
  .fig-green  { fill: #f0f4ef !important; }
  .fig-water  { fill: #eef3f7 !important; }
  .fig-label  { fill: #333333 !important; }
  .fig-accent { fill: #2c8c86 !important; }
  .fig-orbit  { stroke: #2c8c86 !important; }
  .fig-grid   { stroke: #dddddd !important; }
  .fig-stroke-accent { stroke: #2c8c86 !important; }
  .band, .band-alt, .card, .pillar > div, .figure, .offer > div, .note {
    background: #fff !important;
    border-color: #bbb !important;
    box-shadow: none !important;
  }
  .band-ink { background: #fff !important; }
  .band-ink h2, .band-ink h3, .band-ink h4, .band-ink .lede { color: #000 !important; }
  h1, h2, h3, h4, p, li, td, th, strong, .lede, .muted { color: #000 !important; }
  a { color: #000 !important; text-decoration: underline; }
  section { padding: 1.2rem 0; break-inside: avoid; }
  .card, .figure, .pillar > div, .offer > div, .steps > li { break-inside: avoid; }
}
