/* ==========================================================================
   RadarHero website
   Sections follow the order of index.html.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Base
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 400;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.is-locked {
  overflow: hidden;
}

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

a {
  color: var(--accent-text);
  text-decoration-color: color-mix(in srgb, var(--accent-text) 40%, transparent);
  text-underline-offset: 0.2em;
}

a:hover {
  text-decoration-color: currentColor;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

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

::selection {
  background: var(--accent-soft-strong);
  color: var(--ink);
}

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% -120%;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--accent-fill);
  color: var(--on-accent);
  border-radius: 0 0 var(--radius-control) var(--radius-control);
  text-decoration: none;
  font-weight: 500;
}

.skip-link:focus-visible {
  translate: -50% 0;
}

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

/* --------------------------------------------------------------------------
   2. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  text-wrap: balance;
}

/* Tracking is size specific: large type tightens, body sits near zero. */
.t-display {
  font-size: clamp(2.1rem, 4.3vw, 3.55rem);
  line-height: 1.05;
  letter-spacing: -0.034em;
  font-weight: 600;
}

.t-h2 {
  font-size: clamp(1.85rem, 3.5vw, 2.9rem);
  line-height: 1.1;
  letter-spacing: -0.028em;
}

.t-h3 {
  font-size: clamp(1.1rem, 1.5vw, 1.3rem);
  line-height: 1.32;
  letter-spacing: -0.014em;
}

.t-lead {
  font-size: clamp(1.075rem, 1.5vw, 1.25rem);
  line-height: 1.55;
  letter-spacing: -0.006em;
  color: var(--ink-muted);
  max-width: 46ch;
}

.t-body {
  color: var(--ink-muted);
  max-width: 62ch;
}

.t-small {
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--ink-muted);
}

.t-fine {
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ink-faint);
}

.t-num {
  font-family: var(--font-mono);
  font-feature-settings: "tnum" 1;
  letter-spacing: -0.02em;
}

/* Marker highlight behind a single word in a headline. Used once on the page,
   on the word the section turns on. clone keeps the shape intact if the word
   wraps; the negative margin cancels the padding so the word does not shift
   the line it sits in. */
.hl {
  position: relative;
  isolation: isolate;
  padding-inline: 0.17em;
}

/* Painted as a pseudo element rather than a background on the span, because an
   inline background fills the font's full ascent to descent box and reads far
   taller than the word. The insets trim that slack so the band hugs the
   letters, the way a marker would. */
.hl::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0.17em 0 0.2em;
  border-radius: 6px;
  background: var(--accent-soft-strong);
}

p {
  margin: 0;
}

.stack > * + * {
  margin-top: var(--stack, 1rem);
}

/* Wordmark: RADAR bold, HERO extra light. Reproduced in type so it inherits
   the theme colour instead of shipping two inverted bitmaps. */
.wordmark {
  font-family: var(--font-wordmark);
  font-size: var(--wordmark-size, 1.4rem);
  line-height: 1;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  display: inline-block;
}

.wordmark b {
  font-weight: 700;
}

.wordmark span {
  font-weight: 200;
}

/* --------------------------------------------------------------------------
   3. Layout
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--section-y);
  position: relative;
}

.section--sunken {
  background: var(--surface-sunken);
}

.section-head {
  max-width: 42ch;
  margin-bottom: clamp(2.5rem, 4.5vw, 3.75rem);
}

.section-head p {
  margin-top: 1.125rem;
}

.rule {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--line);
}

/* --------------------------------------------------------------------------
   4. Icons and buttons
   -------------------------------------------------------------------------- */

.icon {
  width: 1.25em;
  height: 1.25em;
  fill: currentColor;
  flex: none;
}

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  --btn-line: var(--line-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.8rem 1.4rem;
  min-height: 48px;
  border: 1px solid var(--btn-line);
  border-radius: var(--radius-control);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition:
    background var(--dur-ui) var(--ease-settle),
    border-color var(--dur-ui) var(--ease-settle),
    transform var(--dur-tap) var(--ease-out),
    box-shadow var(--dur-ui) var(--ease-settle);
}

/* Feedback lands on press, not on release. */
.btn:active {
  transform: translateY(1px) scale(0.985);
  transition-duration: var(--dur-tap);
}

.btn--primary {
  --btn-bg: var(--accent-fill);
  --btn-fg: var(--on-accent);
  --btn-line: var(--accent-fill);
  box-shadow: var(--shadow-card);
}

.btn--primary:hover {
  --btn-bg: var(--accent-fill-hover);
  --btn-line: var(--accent-fill-hover);
  box-shadow: var(--shadow-panel);
}

.btn--ghost:hover {
  --btn-bg: var(--accent-soft);
  --btn-line: var(--accent-fill);
}

.btn--onDark {
  --btn-fg: var(--ink-invert);
  --btn-line: var(--line-invert);
}

.btn--onDark:hover {
  --btn-bg: rgb(255 255 255 / 0.09);
  --btn-line: rgb(255 255 255 / 0.34);
}

.btn--sm {
  padding: 0.55rem 1rem;
  min-height: 40px;
  font-size: 0.875rem;
}

.btn--full {
  width: 100%;
}

.btn .icon {
  width: 1.05em;
  height: 1.05em;
  transition: translate var(--dur-ui) var(--ease-settle);
}

.btn:hover .icon-arrow {
  translate: 3px 0;
}

.iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition:
    background var(--dur-ui) var(--ease-settle),
    border-color var(--dur-ui) var(--ease-settle);
}

.iconbtn:hover {
  background: var(--accent-soft);
  border-color: var(--accent-fill);
}

.iconbtn:active {
  transform: scale(0.94);
}

.iconbtn .icon {
  width: 20px;
  height: 20px;
}

/* The theme control is a convenience, not an action. The page already follows
   the system setting, so the button loses its box and sits back until hovered.
   34px keeps it above the 24px minimum target size while reading as quiet. */
.theme-toggle {
  width: 34px;
  height: 34px;
  border-color: transparent;
  background: transparent;
  color: var(--ink-faint);
}

.theme-toggle:hover {
  background: transparent;
  border-color: transparent;
  color: var(--ink);
}

.theme-toggle .icon {
  width: 17px;
  height: 17px;
}

/* Applied by JS only for the length of a toggle, so first paint is never
   transitioned and the page still snaps instantly to the stored theme. */
.theme-anim,
.theme-anim *,
.theme-anim *::before,
.theme-anim *::after {
  transition:
    background-color 260ms var(--ease-settle),
    border-color 260ms var(--ease-settle),
    color 260ms var(--ease-settle) !important;
}

/* Theme toggle swaps the glyph that represents the mode you can switch to. */
[data-theme="dark"] .theme-toggle .icon-moon,
.theme-toggle .icon-sun {
  display: none;
}

[data-theme="dark"] .theme-toggle .icon-sun,
.theme-toggle .icon-moon {
  display: block;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-moon {
    display: none;
  }
  :root:not([data-theme="light"]) .theme-toggle .icon-sun {
    display: block;
  }
}

/* --------------------------------------------------------------------------
   5. Navigation
   -------------------------------------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: var(--glass);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  transition: box-shadow var(--dur-ui) var(--ease-settle);
}

/* Scroll edge effect instead of a hard 1px divider. */
.nav::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 100%;
  height: 20px;
  pointer-events: none;
  background: linear-gradient(to bottom, var(--glass), transparent);
  opacity: 0;
  transition: opacity var(--dur-ui) var(--ease-settle);
}

.nav[data-stuck="true"]::after {
  opacity: 1;
}

.nav[data-stuck="true"] {
  box-shadow: 0 1px 0 var(--line);
}

.nav__inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  height: 72px;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-inline: auto;
  list-style: none;
  padding: 0;
}

.nav__links a {
  display: block;
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-control);
  font-size: 0.9375rem;
  font-weight: 450;
  color: var(--ink-muted);
  text-decoration: none;
  transition:
    color var(--dur-ui) var(--ease-settle),
    background var(--dur-ui) var(--ease-settle);
}

.nav__links a:hover {
  color: var(--ink);
  background: var(--accent-soft);
}

.nav__links a[aria-current="true"] {
  color: var(--ink);
  background: var(--accent-soft);
}

.nav__actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.nav__burger {
  display: none;
}

/* Mobile drawer. Enters and exits along the same path. */
.drawer {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  display: grid;
  grid-template-rows: auto 1fr;
  background: var(--surface);
  translate: 0 -100%;
  visibility: hidden;
  transition:
    translate 420ms var(--ease-settle),
    visibility 0s linear 420ms;
}

.drawer[data-open="true"] {
  translate: 0 0;
  visibility: visible;
  transition:
    translate 420ms var(--ease-settle),
    visibility 0s;
}

.drawer__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 72px;
  padding-inline: var(--gutter);
  border-bottom: 1px solid var(--line);
}

.drawer__body {
  padding: 1.5rem var(--gutter) 2.5rem;
  overflow-y: auto;
}

.drawer__links {
  list-style: none;
  margin: 0 0 2rem;
  padding: 0;
}

.drawer__links a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 1.3rem;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}

.drawer__links .icon {
  color: var(--ink-faint);
  width: 18px;
  height: 18px;
}

/* --------------------------------------------------------------------------
   6. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  padding-top: clamp(2.5rem, 5vw, 4.5rem);
  padding-bottom: var(--section-y);
  overflow: hidden;
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  min-height: min(74dvh, 640px);
}

.hero__copy {
  --stack: 1.6rem;
  max-width: none;
}

.hero__copy .t-lead {
  max-width: 40ch;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.hero__stage {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  border-radius: var(--radius-panel);
  overflow: hidden;
  background:
    radial-gradient(120% 100% at 70% 15%, var(--accent-soft), transparent 62%),
    var(--surface-raised);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-panel);
}

/* Class rather than an element selector, so overlay canvases keep their own
   size instead of being caught by a descendant rule. */
.stage-gl {
  width: 100%;
  height: 100%;
}

/* Live readout overlaid on the field, so the visual states what it shows. */
.hero__readout {
  position: absolute;
  left: 1.25rem;
  bottom: 1.25rem;
  right: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0.95rem;
  border-radius: var(--radius-media);
  border: 1px solid var(--line);
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(170%);
  -webkit-backdrop-filter: blur(16px) saturate(170%);
  font-size: 0.8125rem;
  color: var(--ink-muted);
}

.hero__readout strong {
  color: var(--ink);
  font-weight: 500;
}

/* --------------------------------------------------------------------------
   7. Stakes
   -------------------------------------------------------------------------- */

.stakes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.75rem, 3.5vw, 3rem);
  align-items: start;
}

.stakes__item {
  --stack: 0.7rem;
  padding-top: 1.5rem;
  border-top: 2px solid var(--ink);
}

.stakes__item:nth-child(2) {
  border-top-color: var(--accent-fill);
}

.stakes__figure {
  font-family: var(--font-mono);
  font-size: clamp(2.4rem, 4.2vw, 3.4rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.05em;
  color: var(--ink);
}

.stakes__item:nth-child(2) .stakes__figure {
  color: var(--accent-text);
}

/* --------------------------------------------------------------------------
   8. How it works: pinned canvas, scroll-driven steps
   -------------------------------------------------------------------------- */

.works {
  position: relative;
  background: var(--surface-sunken);
  padding-block: var(--section-y);
}

.works__layout {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

.works__sticky {
  position: sticky;
  top: calc(72px + 2rem);
}

.works__stage {
  position: relative;
  aspect-ratio: 4 / 5;
  max-height: calc(100dvh - 12rem);
  border-radius: var(--radius-panel);
  overflow: hidden;
  background: var(--surface-invert);
  box-shadow: var(--shadow-panel);
}

/* Rolling readout of the field energy the scene is computing. */
.works__trace {
  position: absolute;
  left: 1.25rem;
  bottom: 5.1rem;
  width: calc(100% - 2.5rem);
  height: 62px;
  opacity: 0.9;
  pointer-events: none;
}

.works__caption {
  position: absolute;
  left: 1.25rem;
  right: 1.25rem;
  bottom: 1.25rem;
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius-media);
  border: 1px solid var(--line-invert);
  background: rgb(9 20 25 / 0.62);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--ink-invert);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  letter-spacing: -0.01em;
  transition: opacity var(--dur-ui) var(--ease-settle);
}

.works__caption b {
  font-weight: 500;
  color: var(--accent-text);
}

.works__steps {
  --stack: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The inactive state is carried by heading colour and a rule, never by
   dimming the body copy: any opacity here would drop muted text below AA. */
.works__step {
  --stack: 0.9rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 58vh;
  /* The indent is constant. Only the rule's colour changes, so becoming the
     active step never animates a layout property and never shifts the text
     sideways under the reader. */
  padding: clamp(2rem, 4vw, 3rem) 0 clamp(2rem, 4vw, 3rem) 1.5rem;
  border-bottom: 1px solid var(--line);
  border-left: 2px solid transparent;
  transition: border-color 450ms var(--ease-settle);
}

.works__step:last-child {
  border-bottom: 0;
}

.works__step[data-active="true"] {
  border-left-color: var(--accent-fill);
}

.works__step h3 {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  color: var(--ink-muted);
  transition: color 450ms var(--ease-settle);
}

.works__step[data-active="true"] h3 {
  color: var(--ink);
}

.works__step .t-num {
  font-size: 0.9rem;
  color: var(--ink-faint);
  transition: color 450ms var(--ease-settle);
}

.works__step[data-active="true"] .t-num {
  color: var(--accent-text);
}

.works__spec {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  padding: 0;
  margin: 0;
  list-style: none;
}

.works__spec li {
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   9. System bento
   -------------------------------------------------------------------------- */

.bento {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(0.85rem, 1.4vw, 1.15rem);
}

/* Two-item variant: two .tile--wide cards then span the full row each,
   stacking cleanly instead of leaving a spare third column empty. */
.bento--pair {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.tile {
  --stack: 0.7rem;
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.5rem, 2.4vw, 2rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--surface-raised);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}


.tile--wide {
  grid-column: span 2;
}

/* Cell 1: photographic. Cell 5: brand field. The rest stay plain so the
   grid has real background variation rather than five identical cards. */
.tile--media {
  padding: 0;
  min-height: 300px;
  justify-content: flex-end;
  background:
    linear-gradient(150deg, var(--brand-petrol), #24505f);
}

.tile--media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.5;
  mix-blend-mode: luminosity;
}

.tile--media .tile__body {
  position: relative;
  padding: clamp(1.5rem, 2.4vw, 2rem);
  color: var(--ink-invert);
  background: linear-gradient(to top, rgb(9 20 25 / 0.86), transparent);
}

.tile--media .t-body {
  color: var(--ink-invert-muted);
}

.tile--alert {
  background: var(--surface-invert);
  border-color: transparent;
  color: var(--ink-invert);
}

.tile--alert .mark {
  color: var(--accent-text);
}

.tile--alert .t-body {
  color: var(--ink-invert-muted);
}

.tile--field {
  background:
    radial-gradient(90% 130% at 12% 100%, var(--accent-soft-strong), transparent 58%),
    repeating-linear-gradient(
      90deg,
      var(--line) 0 1px,
      transparent 1px 26px
    ),
    var(--surface-raised);
}

.tile__list {
  --stack: 0;
  list-style: none;
  margin: 0.35rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.tile__list li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.9375rem;
  color: var(--ink-invert-muted);
}

.tile__list .icon {
  width: 17px;
  height: 17px;
  margin-top: 0.28em;
  color: var(--accent-text);
}

/* Feature marks. Phosphor duotone at optical size, set directly on the
   surface. The 0.2-opacity shape inside each glyph supplies the second tone,
   so one colour produces two, and the marks read as drawn rather than
   dropped into a tinted chip. */
.mark {
  width: 30px;
  height: 30px;
  margin-bottom: 0.5rem;
  color: var(--accent-text);
  fill: currentColor;
  flex: none;
}

.mark--muted {
  margin-bottom: 0;
  color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   10. Privacy
   -------------------------------------------------------------------------- */

.privacy {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.86fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
}

/* Featured first, the rest paired. Five identical stacked cards is the shape
   a template produces; the camera is also the objection that actually decides
   this purchase, so it earns the width. */
.denies {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}

.deny:first-child {
  grid-column: 1 / -1;
}

.deny:first-child h3 {
  font-size: 1.3rem;
  letter-spacing: -0.02em;
}

.deny:first-child p {
  font-size: 1rem;
}

.deny {
  --stack: 0.3rem;
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr);
  gap: 1.15rem;
  align-items: start;
  padding: 1.35rem 1.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--surface-raised);
}


.deny h3 {
  font-size: 1.0625rem;
  letter-spacing: -0.012em;
}

.deny p {
  font-size: 0.9375rem;
  color: var(--ink-muted);
}

/* Inverted panel is the brand container from the corporate design, not a
   theme flip: it stays petrol in light mode and lifts in dark mode. */
.panel-dark {
  --stack: 1.15rem;
  padding: clamp(1.75rem, 3vw, 2.5rem);
  border-radius: var(--radius-panel);
  background: var(--surface-invert);
  color: var(--ink-invert);
  box-shadow: var(--shadow-panel);
}

.panel-dark h3 {
  font-size: clamp(1.2rem, 1.8vw, 1.45rem);
  letter-spacing: -0.02em;
}

.panel-dark p {
  color: var(--ink-invert-muted);
  font-size: 0.9375rem;
}

.payload {
  --stack: 0;
  display: grid;
  gap: 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.payload li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius-control);
  background: var(--surface-invert-raised);
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--ink-invert);
}

.payload span {
  color: var(--ink-invert-muted);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.8rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-invert);
  font-size: 0.8125rem;
  color: var(--ink-invert);
}

.badge .icon {
  width: 16px;
  height: 16px;
  color: var(--accent-text);
}

a.badge {
  color: var(--ink-invert);
  text-decoration: none;
  transition:
    background var(--dur-ui) var(--ease-settle),
    border-color var(--dur-ui) var(--ease-settle);
}

a.badge:hover {
  background: rgb(255 255 255 / 0.08);
  border-color: rgb(255 255 255 / 0.34);
}

.prose code {
  padding: 0.1em 0.4em;
  border-radius: 5px;
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.875em;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   11. Pricing
   -------------------------------------------------------------------------- */

.price {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(1.5rem, 3.5vw, 3rem);
  align-items: center;
  padding: clamp(1.75rem, 3.5vw, 3rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--surface-raised);
  box-shadow: var(--shadow-panel);
}

.price__figures {
  display: grid;
  gap: 1.5rem;
}

.price__row {
  --stack: 0.2rem;
  display: grid;
  gap: 0.15rem;
}

.price__value {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: clamp(2.1rem, 3.6vw, 2.9rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.05em;
  color: var(--ink);
}

.price__value small {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-muted);
}

.price__label {
  font-size: 0.9375rem;
  color: var(--ink-muted);
}

.price__detail {
  --stack: 1.15rem;
  padding-left: clamp(0rem, 3vw, 2.5rem);
  border-left: 1px solid var(--line);
}

.checklist {
  --stack: 0;
  display: grid;
  gap: 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.checklist li {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 0.9375rem;
  color: var(--ink-muted);
}

.checklist .icon {
  width: 18px;
  height: 18px;
  margin-top: 0.26em;
  color: var(--accent-text);
}

/* --------------------------------------------------------------------------
   12. Contact
   -------------------------------------------------------------------------- */

.contact {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

.contact__aside {
  --stack: 1.5rem;
}

.contact__direct {
  --stack: 0;
  display: grid;
  gap: 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.contact__direct li {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  font-size: 0.9375rem;
}

.contact__direct .icon {
  width: 18px;
  height: 18px;
  color: var(--ink-faint);
}

.form {
  display: grid;
  gap: 1.15rem;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  background: var(--surface-raised);
  box-shadow: var(--shadow-card);
}

.form__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.15rem;
}

.field {
  display: grid;
  gap: 0.5rem;
}

.field > label {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink);
}

.field__hint {
  font-size: 0.8125rem;
  color: var(--ink-muted);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.8rem 0.95rem;
  min-height: 48px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.9375rem;
  transition:
    border-color var(--dur-ui) var(--ease-settle),
    box-shadow var(--dur-ui) var(--ease-settle);
}

.field textarea {
  min-height: 128px;
  resize: vertical;
}

.field select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 20px) calc(50% + 2px),
    calc(100% - 14px) calc(50% + 2px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 2.75rem;
}

/* Placeholder passes AA against the input background. */
.field ::placeholder {
  color: var(--ink-faint);
  opacity: 1;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent-fill);
  box-shadow: 0 0 0 3px var(--accent-soft-strong);
}

.field__error {
  display: none;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.8125rem;
  color: var(--danger-text);
}

.field__error .icon {
  width: 15px;
  height: 15px;
}

.field[data-invalid="true"] input,
.field[data-invalid="true"] select,
.field[data-invalid="true"] textarea {
  border-color: var(--danger-text);
  background: var(--danger-soft);
}

.field[data-invalid="true"] .field__error {
  display: flex;
}

.field--check {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 0.75rem;
}

.field--check input {
  width: 20px;
  height: 20px;
  min-height: 0;
  margin-top: 0.15em;
  padding: 0;
  accent-color: var(--accent-fill);
}

.field--check label {
  font-weight: 400;
  font-size: 0.875rem;
  color: var(--ink-muted);
  line-height: 1.55;
}

.field--check .field__error {
  grid-column: 1 / -1;
}

.form__submit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}

.form[data-state="sending"] .btn--primary {
  pointer-events: none;
  opacity: 0.72;
}

.form__spinner {
  display: none;
}

.form[data-state="sending"] .form__spinner {
  display: block;
  animation: spin 900ms linear infinite;
}

.form[data-state="sending"] .form__submit .icon-arrow {
  display: none;
}

@keyframes spin {
  to {
    rotate: 360deg;
  }
}

.form__status {
  display: none;
  align-items: flex-start;
  gap: 0.65rem;
  padding: 0.85rem 1rem;
  border-radius: var(--radius-control);
  font-size: 0.9375rem;
}

.form__status .icon {
  width: 19px;
  height: 19px;
  margin-top: 0.15em;
}

.form[data-state="sent"] .form__status--ok,
.form[data-state="error"] .form__status--err {
  display: flex;
}

.form__status--ok {
  background: var(--success-soft);
  color: var(--success-text);
}

.form__status--err {
  background: var(--danger-soft);
  color: var(--danger-text);
}

/* --------------------------------------------------------------------------
   13. Footer
   -------------------------------------------------------------------------- */

.footer {
  padding-block: clamp(3rem, 6vw, 4.5rem) 2rem;
  border-top: 1px solid var(--line);
  background: var(--surface-sunken);
}

.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(4, minmax(0, 1fr));
  gap: clamp(2rem, 4vw, 3rem);
}

.footer__brand {
  --stack: 1rem;
  max-width: 30ch;
}

.footer__col {
  --stack: 0;
}

.footer__col h4 {
  margin-bottom: 0.9rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink);
}

.footer__col ul {
  display: grid;
  gap: 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer__col a {
  font-size: 0.9375rem;
  color: var(--ink-muted);
  text-decoration: none;
}

.footer__col a:hover {
  color: var(--accent-text);
}

.footer__base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------------------
   13b. Media and graceful degradation
   -------------------------------------------------------------------------- */

/* Photographs sit on a brand field, so a failed request degrades to a
   deliberate surface rather than a broken image box. */
.media-frame {
  width: 100%;
  height: auto;
  border-radius: var(--radius-media);
  border: 1px solid var(--line);
  background: linear-gradient(150deg, var(--brand-petrol), #24505f);
  color: var(--ink-invert);
  font-size: 0.8125rem;
}

/* If WebGL is unavailable the stage keeps its shape and reads as a field. */
[data-fallback] canvas {
  display: none;
}

.hero__stage[data-fallback],
.works__stage[data-fallback] {
  background:
    radial-gradient(70% 70% at 50% 45%, var(--accent-soft-strong), transparent 70%),
    repeating-radial-gradient(
      circle at 50% 45%,
      var(--line) 0 1px,
      transparent 1px 22px
    ),
    var(--surface-raised);
}

.works__stage[data-fallback] .works__trace {
  display: none;
}

/* --------------------------------------------------------------------------
   14. Reveal
   -------------------------------------------------------------------------- */

.reveal-ready [data-reveal] {
  opacity: 0;
  translate: 0 20px;
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    translate var(--dur-reveal) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal-ready [data-reveal][data-shown="true"] {
  opacity: 1;
  translate: 0 0;
}

/* Big surfaces should not slide. A large moving object is the one thing the
   motion guidance asks you to fade instead, and it also stops the page reading
   as one repeated animation applied to everything. */
.reveal-ready .hero__stage[data-reveal],
.reveal-ready .panel-dark[data-reveal],
.reveal-ready .price[data-reveal] {
  translate: none;
  scale: 0.988;
  transition-property: opacity, scale;
}

.reveal-ready .hero__stage[data-reveal][data-shown="true"],
.reveal-ready .panel-dark[data-reveal][data-shown="true"],
.reveal-ready .price[data-reveal][data-shown="true"] {
  scale: 1;
}

/* Section heads lead, so they travel furthest and settle slowest. */
.reveal-ready .section-head[data-reveal] {
  translate: 0 28px;
  transition-duration: 720ms;
}

/* Cards arrive as a group; a long travel on each one reads as noise. */
.reveal-ready .tile[data-reveal],
.reveal-ready .deny[data-reveal],
.reveal-ready .stakes__item[data-reveal] {
  translate: 0 14px;
  transition-duration: 540ms;
}

/* --------------------------------------------------------------------------
   15. Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1024px) {
  .nav__links {
    display: none;
  }

  .nav__cta {
    display: none;
  }

  .nav__burger {
    display: inline-flex;
  }

  .nav__actions {
    margin-left: auto;
  }

  .hero__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
    min-height: 0;
  }

  .hero__copy {
    max-width: 30ch;
  }

  .hero__stage {
    aspect-ratio: 5 / 4;
  }

  /* The animation is the explanation, so it stays pinned on narrow screens
     instead of scrolling away above the text. Block layout rather than grid,
     so the sticky item's containing block is the whole section and it can
     actually travel. The steps scroll underneath it. */
  .works__layout {
    display: block;
  }

  /* Flush with the nav and opaque, so text scrolling underneath is covered
     rather than peeking through a gap. */
  .works__sticky {
    position: sticky;
    top: 72px;
    z-index: 1;
    padding-block: 0.75rem 0.25rem;
    background: var(--surface-sunken);
  }

  .works__stage {
    aspect-ratio: auto;
    height: 40dvh;
    min-height: 260px;
    max-height: 420px;
  }

  .works__trace {
    bottom: 5.6rem;
    height: 42px;
  }

  .works__caption {
    bottom: 0.9rem;
    left: 0.9rem;
    right: 0.9rem;
    padding: 0.7rem 0.85rem;
    font-size: 0.75rem;
  }

  .works__steps {
    margin-top: 1.25rem;
  }

  .works__step {
    min-height: 62dvh;
  }

  .privacy,
  .contact,
  .price {
    grid-template-columns: minmax(0, 1fr);
  }

  .price__detail {
    padding-left: 0;
    padding-top: 1.5rem;
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer__brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 760px) {
  body {
    font-size: 1rem;
  }

  .stakes {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.75rem;
  }

  .bento {
    grid-template-columns: minmax(0, 1fr);
  }

  .tile--wide {
    grid-column: span 1;
  }

  .form__row {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero__actions .btn {
    flex: 1 1 auto;
  }

  .hero__readout {
    left: 0.85rem;
    right: 0.85rem;
    bottom: 0.85rem;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
  }
}

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

  .deny {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
  }

  .denies {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --------------------------------------------------------------------------
   16. User preferences
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .reveal-ready [data-reveal] {
    opacity: 1;
    translate: none;
  }

  .drawer {
    transition: none;
  }

  .works__step {
    transition: none;
  }

  .theme-anim,
  .theme-anim *,
  .theme-anim *::before,
  .theme-anim *::after {
    transition: none !important;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .nav,
  .hero__readout {
    background: var(--surface);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .nav::after {
    display: none;
  }

  .works__caption {
    background: #091419;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

@media (prefers-contrast: more) {
  :root {
    --line: rgb(22 47 58 / 0.42);
    --line-strong: rgb(22 47 58 / 0.62);
    --ink-muted: #2b4450;
    --ink-faint: #405a66;
  }

  :root[data-theme="dark"] {
    --line: rgb(240 233 228 / 0.4);
    --line-strong: rgb(240 233 228 / 0.62);
    --ink-muted: #d3e0e6;
    --ink-faint: #b6c7cf;
  }

  .nav,
  .hero__readout {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--surface);
  }
}

/* --------------------------------------------------------------------------
   17. Sub pages: legal text and the not-found page
   -------------------------------------------------------------------------- */

.pagehead {
  padding-block: clamp(3rem, 6vw, 5rem) clamp(2rem, 4vw, 3rem);
  border-bottom: 1px solid var(--line);
}

.pagehead .t-h2 {
  max-width: 22ch;
}

.pagehead p {
  margin-top: 1rem;
}

.notice {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  max-width: 72ch;
  margin-top: 2rem;
  padding: 1rem 1.15rem;
  border: 1px solid var(--accent-fill);
  border-radius: var(--radius-card);
  background: var(--accent-soft);
  font-size: 0.9375rem;
  color: var(--ink);
}

.notice .icon {
  width: 20px;
  height: 20px;
  margin-top: 0.15em;
  color: var(--accent-text);
}

.prose {
  max-width: 72ch;
  padding-block: clamp(2.5rem, 5vw, 4rem);
}

.prose h2 {
  margin-top: 3rem;
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
}

.prose h2:first-child {
  margin-top: 0;
}

.prose h3 {
  margin-top: 2rem;
  font-size: 1.0625rem;
  letter-spacing: -0.012em;
}

.prose p,
.prose ul,
.prose dl {
  margin-top: 1rem;
  color: var(--ink-muted);
}

.prose ul {
  padding-left: 1.15rem;
}

.prose li + li {
  margin-top: 0.5rem;
}

.prose li::marker {
  color: var(--accent-text);
}

/* Key/value rows for the Impressum. Sparse, no rule under every line. */
.prose dl {
  display: grid;
  grid-template-columns: minmax(11rem, auto) minmax(0, 1fr);
  gap: 0.65rem 1.75rem;
}

.prose dt {
  font-weight: 500;
  color: var(--ink);
}

.prose dd {
  margin: 0;
}

/* Slots the operator still has to fill in. Deliberately loud. */
.fill {
  display: inline-block;
  padding: 0.05em 0.4em;
  border-radius: 4px;
  background: var(--accent-soft-strong);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.85em;
}

.prose__updated {
  margin-top: 3rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}

.notfound {
  display: grid;
  gap: 1.75rem;
  align-content: center;
  justify-items: start;
  min-height: 62dvh;
  padding-block: var(--section-y);
}

.notfound__code {
  font-family: var(--font-mono);
  font-size: clamp(3.5rem, 9vw, 6rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.05em;
  color: var(--accent-text);
}

.notfound__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

@media (max-width: 640px) {
  .prose dl {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.2rem;
  }

  .prose dd + dt {
    margin-top: 0.9rem;
  }
}

/* --------------------------------------------------------------------------
   18. Team page
   -------------------------------------------------------------------------- */

/* The nav marks a whole page, not a scrolled-to section. The scrollspy in
   main.js writes aria-current="true" and only ever touches links that resolve
   to a section on the current page, so "page" survives untouched. */
.nav__links a[aria-current="page"] {
  color: var(--ink);
  background: var(--accent-soft);
}

/* Drawer rows run edge to edge, so a filled chip would bleed into the gutter.
   Colour carries the state there instead. */
.drawer__links a[aria-current="page"] {
  color: var(--accent-text);
}

/* Prose set inside a .section, which already carries the vertical rhythm. */
.prose--flush {
  padding-block: 0;
}

/* Two people across, one below 760px. Same gap as the bento so both grids
   read as one system. */
.team-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.85rem, 1.4vw, 1.15rem);
  max-width: 640px;
}

.person {
  --stack: 1.1rem;
}

/* Deliberately empty. A stock face standing in for a real founder would be a
   lie, so the slot stays a labelled brand surface until a portrait exists.
   Dashed border and caption say "missing" rather than "decorative". */
.person__portrait {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  aspect-ratio: 1 / 1;
  border: 1px dashed color-mix(in srgb, var(--ink-invert) 38%, transparent);
  border-radius: var(--radius-media);
  background: linear-gradient(150deg, var(--brand-petrol), var(--surface-invert-raised));
  color: var(--ink-invert-muted);
}

.person__portrait .icon {
  width: 22px;
  height: 22px;
}

/* A real portrait replaces the "missing" placeholder styling entirely.
   position: relative + an absolutely-filled img is used instead of a plain
   height: 100% child, because percentage heights on a flex item (this sits
   inside .person__portrait's flex column) don't reliably resolve against
   the aspect-ratio box in every browser, which let the image render at its
   intrinsic size and spill out of the card uncropped. */
.person__portrait--photo {
  position: relative;
  border-style: solid;
  border-color: var(--line);
  background: var(--surface-raised);
  overflow: hidden;
  padding: 0;
}

.person__portrait--photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
  border-radius: inherit;
}

.person__slot {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: -0.01em;
}

.person__body {
  --stack: 0.5rem;
}

.person__role {
  font-size: 0.9375rem;
  color: var(--ink-muted);
}

.team-note {
  margin-top: clamp(1.5rem, 3vw, 2rem);
}

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

  /* One column: a full width square portrait would push the copy off screen. */
  .person__portrait {
    aspect-ratio: 16 / 9;
  }
}

/* --------------------------------------------------------------------------
   19. Timeline page
   -------------------------------------------------------------------------- */

.timeline {
  --timeline-line: var(--line);
  display: grid;
  gap: 0;
  max-width: 760px;
}

.timeline__item {
  position: relative;
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: clamp(1rem, 2.5vw, 2rem);
  padding-block: clamp(1.25rem, 3vw, 1.75rem);
}

/* The connecting line and dot sit in the gap between date and body, not on
   top of either column, so it never competes with text. */
.timeline__item::before {
  content: "";
  position: absolute;
  left: calc(8.5rem + clamp(1rem, 2.5vw, 2rem) / 2 - 1px);
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--timeline-line);
}

.timeline__item:first-child::before {
  top: 1.6rem;
}

.timeline__item:last-child::before {
  bottom: calc(100% - 1.6rem);
}

.timeline__dot {
  position: absolute;
  left: calc(8.5rem + clamp(1rem, 2.5vw, 2rem) / 2 - 6px);
  top: clamp(1.25rem, 3vw, 1.75rem);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent-fill);
}

.timeline__item[data-status="done"] .timeline__dot {
  background: var(--accent-fill);
}

/* The most recent milestone reads as "happening now": a filled dot plus a
   radar-style ping expanding outward, on brand for a company that measures
   rooms with radio waves. Reduced motion already freezes every ::after
   animation site-wide, so this needs no separate override. */
.timeline__item[data-status="current"] .timeline__dot {
  background: var(--accent-fill);
}

.timeline__item[data-status="current"] .timeline__dot::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 2px solid var(--accent-fill);
  animation: timeline-ping 2200ms cubic-bezier(0.16, 1, 0.3, 1) infinite;
}

@keyframes timeline-ping {
  0% {
    scale: 0.6;
    opacity: 0.85;
  }
  100% {
    scale: 2.1;
    opacity: 0;
  }
}

.timeline__tag {
  display: inline-flex;
  align-items: center;
  margin-left: 0.5rem;
  padding: 0.1rem 0.55rem;
  border-radius: var(--radius-pill);
  background: var(--accent-soft-strong);
  color: var(--accent-text);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.02em;
  vertical-align: middle;
}

/* The line grows downward into each dot and the dot pops in just behind it,
   both gated by the same [data-shown] the sitewide reveal system already
   sets on this element, so scrolling through reads as the line drawing
   itself forward through the company's history rather than a static
   diagram with text sliding past a line that was always fully there. */
.reveal-ready .timeline__item[data-reveal]::before {
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 640ms var(--ease-out);
  transition-delay: calc(var(--reveal-delay, 0ms) + 100ms);
}

.reveal-ready .timeline__item[data-reveal][data-shown="true"]::before {
  transform: scaleY(1);
}

.reveal-ready .timeline__dot {
  scale: 0;
  transition: scale 360ms var(--ease-out);
  transition-delay: calc(var(--reveal-delay, 0ms) + 620ms);
}

.reveal-ready .timeline__item[data-shown="true"] .timeline__dot {
  scale: 1;
}

.timeline__date {
  padding-top: 0.15rem;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  color: var(--ink-muted);
}

.timeline__body {
  --stack: 0.4rem;
  padding-left: clamp(1.5rem, 3vw, 2.25rem);
}

@media (max-width: 640px) {
  .timeline__item {
    grid-template-columns: 1fr;
    gap: 0.5rem;
    padding-left: 1.5rem;
  }

  .timeline__item::before {
    left: 5px;
  }

  .timeline__dot {
    left: 0;
  }

  .timeline__body {
    padding-left: 0;
  }
}
