/* sixth sense — landing page
   Rules source: vault note "UI design rules - landing page.md"
   Dark field. One signal per viewport. Gradient = emergence only. Orange used once. */

:root {
  /* draft tokens — warm-leaning near-black; open question in UI rules */
  --bg: #0b0a0c;
  --text: #f2efe9;
  --muted: #b8b1a6;
  --purple: #b49cff;
  --blue: #8fb6ff;
  --orange: #ff9552;

  /* The glitch palette, sampled from the wordmark. Declared here because three separate
     things now draw from it: the wordmark itself, the vision signal's bars, and the
     vision copy's accents. */
  --glitch-magenta: #ea33f7;
  --glitch-cyan: #75fbfd;
  --glitch-silver: #c0c0c0;
  --glitch-yellow: #f7e733;
  --glitch-red: #f73333;
  --glitch-blue: #3a4cff;

  --font-display: "Fraunces", Georgia, serif;
  --font-body: "Inter", -apple-system, sans-serif;

  /* 4-size scale */
  --size-display: clamp(3rem, 8vw, 5.5rem);
  --size-h2: 1.375rem;
  --size-body: 1.0625rem;
  --size-small: 0.875rem;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  /* full-width clip: contains the map's centered breakout so it never scrolls the
     page sideways, without cutting the map (it sits within the viewport). */
  overflow-x: clip;
}

/* ---------- top nav ---------- */

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--text);
  color: var(--bg);
  padding: 0.5rem 0.8rem;
  border-radius: 4px;
  font-size: var(--size-small);
}

.skip-link:focus { left: 8px; top: 8px; }

/* scroll progress — JS scales it 0→1; stays invisible (scaleX 0) without JS */
.progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--purple);
  transform: scaleX(0);
  transform-origin: 0 50%;
  z-index: 60;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .progress { display: none; }
}

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem clamp(16px, 4vw, 32px);
  background: rgba(11, 10, 12, 0.55);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid rgba(242, 239, 233, 0.08);
}

.nav-brand {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}

.nav-links {
  list-style: none;
  display: flex;
  align-items: center;
  gap: clamp(1.1rem, 2.4vw, 1.75rem);   /* tab-style spacing: roomy, even gaps */
}

/* A crisp underline draws in on hover/focus rather than just appearing — a rule in from the
   left edge, not a fade. Built on background-size instead of border so it doesn't shift layout. */
.nav-links a {
  position: relative;
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0;
  white-space: nowrap;
  padding-bottom: 6px;
  background-image: linear-gradient(var(--glitch-cyan), var(--glitch-cyan));
  background-repeat: no-repeat;
  background-position: left bottom;
  background-size: 0% 1px;
  transition: color 120ms ease, background-size 140ms ease;
}

.nav-links .nav-icon { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; padding: 0; background-image: none; }
.nav-links .nav-icon svg { display: block; }
.nav-links .nav-icon:hover, .nav-links .nav-icon:focus-visible { color: var(--text); }
.nav-links a:hover, .nav-links a:focus-visible, .nav-links a[aria-current="page"] { color: var(--text); background-size: 100% 1px; }
.nav-links a[aria-current="page"] { background-image: linear-gradient(currentColor, currentColor); }

@media (prefers-reduced-motion: reduce) {
  .nav-links a { transition: color 120ms ease; }
}

@media (max-width: 560px) {
  .nav { justify-content: center; }
  .nav-brand { display: none; }  /* brand hides; the three links center */
  .nav-links { gap: 1.25rem; }
}

/* anchored headings clear the sticky nav; smooth unless reduced-motion */
h2 { scroll-margin-top: 4.75rem; }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* ---------- hero ---------- */

.hero {
  position: relative;
  min-height: 92vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  text-align: center;
}

/* A static field, not an animation — the brief is explicit that the grid stays stable while
   everything else glitches around it. Plain CSS lines, no JS, no per-cell content: this replaced
   the old code-fragment matrix grid, which this page no longer runs. */
.hero-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image:
    linear-gradient(to right, rgba(242, 239, 233, 0.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(242, 239, 233, 0.055) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 75% 70% at 50% 45%, black 40%, transparent 92%);
  mask-image: radial-gradient(ellipse 75% 70% at 50% 45%, black 40%, transparent 92%);
}

/* Debris near the edges, in the wordmark's own palette plus three accents reserved for this
   moment only — rare enough that the "orange is rarest" rule still holds for everything else.
   They sit at a quiet resting opacity and only jump during the fault line's pass (below); the
   motion is on transform/opacity only, so the grid underneath never has to repaint. */
.hero-fragments { position: absolute; inset: 0; z-index: 1; pointer-events: none; }

.hf { position: absolute; opacity: 0.4; }

.hf--a { left: 2%;  top: 21%; width: 56px; height: 9px;  background: var(--glitch-yellow); }
.hf--b { left: 4%;  top: 24%; width: 16px; height: 6px;  background: var(--text); }
.hf--c { left: 1%;  top: 27%; width: 78px; height: 15px; background: var(--glitch-magenta); }
.hf--d { right: 3%; top: 60%; width: 58px; height: 9px;  background: var(--glitch-cyan); }
.hf--e { right: 1%; top: 64%; width: 86px; height: 16px; background: var(--glitch-red); }
.hf--f { right: 5%; top: 68%; width: 20px; height: 7px;  background: var(--glitch-blue); }

/* The signature move: a thin horizontal line sweeping the full width of the hero. It fires once
   on arrival (triggered by main.js, after the entrance fade settles) and, after that, only on
   interaction — wordmark hover, or clicking the nav brand. Never on a loop. A linear-gradient
   core gives it a faint RGB fringe rather than a flat bar. */
.fault-line {
  position: absolute;
  left: -15%;
  top: 44%;
  z-index: 4;
  width: 130%;
  height: 2px;
  background: linear-gradient(90deg,
    transparent, var(--glitch-cyan) 30%, var(--text) 50%, var(--glitch-magenta) 70%, transparent);
  opacity: 0;
  pointer-events: none;
  transform: translateX(-100%);
}

/* Hero burst timing is defined once in home.css. */

.hero-inner {
  position: relative;
  z-index: 2;
  max-width: 640px;
  padding: 0 24px;
}

/* Motion (main.js) drives all animation. Elements start hidden only when JS is running and
   motion is allowed; .no-motion is set on reduced-motion or CDN failure. The hero's own copy
   fades in together (not staggered — "wordmark and copy fade in together" is explicit) and
   faster than the sections below it, since the brief calls out 500ms specifically for this. */
@media (prefers-reduced-motion: no-preference) {
  html.js:not(.no-motion) [data-hero] {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 500ms cubic-bezier(0.22, 1, 0.36, 1),
                transform 500ms cubic-bezier(0.22, 1, 0.36, 1);
    will-change: opacity, transform;
  }
  html.js:not(.no-motion) [data-animate] {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
                transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
    will-change: opacity, transform;
  }
  html.js:not(.no-motion) [data-hero].in,
  html.js:not(.no-motion) [data-animate].in {
    opacity: 1;
    transform: none;
  }

  /* pieces stagger in after their section. Activity cards rise; senses fade only —
     their translate(-50%, -50%) positioning on the map must not be disturbed. */
  html.js:not(.no-motion) [data-animate] .activities > li {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.6s ease, transform 0.6s ease;
  }
  html.js:not(.no-motion) [data-animate].in .activities > li { opacity: 1; transform: none; }
  html.js:not(.no-motion) [data-animate].in .activities > li:nth-child(2) { transition-delay: 0.09s; }
  html.js:not(.no-motion) [data-animate].in .activities > li:nth-child(3) { transition-delay: 0.18s; }

  html.js:not(.no-motion) [data-animate] .sense { opacity: 0; transition: opacity 0.55s ease; }
  html.js:not(.no-motion) [data-animate].in .sense { opacity: 1; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(2) { transition-delay: 0.12s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(3) { transition-delay: 0.24s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(4) { transition-delay: 0.36s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(5) { transition-delay: 0.48s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(6) { transition-delay: 0.60s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(7) { transition-delay: 0.72s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(8) { transition-delay: 0.84s; }
  html.js:not(.no-motion) [data-animate].in .sense:nth-of-type(9) { transition-delay: 0.96s; }
}

/* The white base stays readable over two decorative colour channels. */
.wordmark {
  position: relative;
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--size-display);
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--text);
}

.wm-base { position: relative; z-index: 2; }

.wm-channel {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  user-select: none;
}

.wm-channel--cyan { color: var(--glitch-cyan); }
.wm-channel--magenta { color: var(--glitch-magenta); }

.hero-statement {
  margin-top: 1.5rem;
  max-width: 34ch;
  margin-inline: auto;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.35rem, 3vw, 1.9rem);
  line-height: 1.3;
  color: var(--text);
  text-wrap: balance;
}

.definition {
  margin-top: 1rem;
  font-family: "Courier New", Courier, monospace;
  font-size: 0.9375rem;
  color: var(--muted);
  letter-spacing: 0.01em;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.9rem;
  margin-top: 2.25rem;
}

/* Buttons: border colour and the arrow nudge on hover/focus, 140ms — the brief's "buttons and
   navigation" row. No underline-draw here; that's the nav links' move, kept separate so the two
   controls don't read as the same affordance. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  padding: 0.7rem 1.3rem;
  border: 1px solid transparent;
  border-radius: 3px;
  font-family: "Courier New", Courier, monospace;
  font-size: 0.875rem;
  text-decoration: none;
  transition: border-color 140ms ease, background-color 140ms ease, color 140ms ease;
}

.btn-arrow { display: inline-block; transition: translate 140ms ease; }
.btn:hover .btn-arrow, .btn:focus-visible .btn-arrow { translate: 3px -3px; }

.btn--primary { background: var(--text); color: var(--bg); border-color: var(--text); }
.btn--primary:hover, .btn--primary:focus-visible { background: var(--glitch-silver); border-color: var(--glitch-silver); }

.btn--outline { background: transparent; color: var(--glitch-cyan); border-color: rgba(117, 251, 253, 0.5); }
.btn--outline:hover, .btn--outline:focus-visible { border-color: var(--glitch-cyan); background: rgba(117, 251, 253, 0.08); }

.btn:focus-visible { outline: 2px solid var(--glitch-cyan); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .nav-links a, .btn, .btn-arrow { transition: none; }
}

.hero-tag {
  position: absolute;
  right: clamp(16px, 4vw, 32px);
  bottom: clamp(16px, 4vw, 28px);
  z-index: 2;
  font-family: "Courier New", Courier, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--muted);
  opacity: 0.6;
}

@media (max-width: 760px) {
  /* "On mobile, use only the entrance effect and button feedback" — the fragments and fault
     line are an edge-of-viewport effect that doesn't survive a narrow screen anyway, so they're
     dropped rather than squeezed. The grid, wordmark, copy and buttons are unaffected. */
  .hero-fragments, .fault-line, .hero-tag { display: none; }
  .hero-grid { background-size: 44px 44px; }
}

/* ---------- what we do ---------- */

/* Sits directly under the vision: the problem is stated, then the thing we do about it.
   The three items below reuse .activities — the site's existing three-up list, which already
   carries its own staggered reveal. */
.offer-body {
  margin-top: 1.5rem;
  margin-bottom: 3rem;
  color: var(--muted);
  max-width: 52ch;
  text-wrap: pretty;
}

/* ---------- sections ---------- */

main {
  max-width: 680px;
  margin: 0 auto;
  padding: 0 24px;
}

section { padding: 5.5rem 0 0; }

h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--size-h2);
  color: var(--muted);
  margin-bottom: 2rem;
}

.activities {
  list-style: none;
  display: grid;
  gap: 2.25rem;
}

.activities h3 {
  font-size: var(--size-body);
  font-weight: 500;
  margin-bottom: 0.35rem;
}

.activities p { color: var(--muted); }

.quiet { color: var(--muted); }

/* The signals themselves. The map is the picture; this is the evidence. Nine dated items,
   each linking to a primary report, rendered as text at every width — nothing is trapped in a
   hover state that a phone can never trigger. */
.signal-list {
  list-style: none;
  width: min(100vw - 2rem, 1000px);
  margin-left: 50%;
  transform: translateX(-50%);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(265px, 1fr));
  gap: 0.5rem 2.25rem;
}

.signal-list > li {
  border-top: 1px solid rgba(242, 239, 233, 0.14);
  padding-top: 0.9rem;
}

.signal-head { font-size: var(--size-body); font-weight: 500; margin-bottom: 0.35rem; }

.signal-body {
  color: var(--muted);
  font-size: var(--size-small);
  line-height: 1.6;
  text-wrap: pretty;
}

/* 44px keeps it a real touch target now that this is the only way to reach the source. */
.signal-source {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;
  font-size: var(--size-small);
  color: var(--muted);
  text-underline-offset: 3px;
}

.signal-source:hover { color: var(--text); }

/* ---------- vision ---------- */

/* breaks out wider than the 680px column; body clip guards it. The reveal transform
   lives on the section, the horizontal breakout on this inner element — no conflict. */
.vision-inner {
  width: min(100vw - 2rem, 1060px);
  margin-left: 50%;
  transform: translateX(-50%);
  display: grid;
  /* The copy carries the section, so it takes the larger share; the signal is its companion,
     top-aligned with the statement rather than floating in the middle of a tall column. */
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

@media (max-width: 780px) {
  /* no breakout on small screens — flow in the normal column so text can't clip.
     minmax(0,…) lets the column shrink below the SVG's intrinsic width. */
  .vision-inner {
    width: auto;
    margin-left: 0;
    transform: none;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
  }
  /* compact on mobile so the signal reads as a deliberate glow, not a lonely dot in a big
     square. A definite width (not just max-width) is required — otherwise the figure
     shrink-wraps its percentage-sized children to 0×0. */
  .vision-figure { width: min(230px, 100%); margin: 0.25rem auto 0; }
}

/* The mission is the page's argument, so it's set as one: a quiet kicker, the problem stated
   once at display size, the detail underneath it in muted body text, and the commitment itself
   pulled out behind an accent rule. Three distinct weights instead of two identical paragraphs
   — the hierarchy is what makes it read as important, not louder words. */
.section-kicker {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1.4rem;
}

/* A marker, not a bullet: it ties the copy to the signal bars sitting beside it. */
.section-kicker .spark {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--glitch-magenta);
}

/* The one display-size line a section is allowed. Shared by the vision and the offer so the
   two read as siblings — the problem stated, then what we do about it. */
.section-lede {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1.16;
  letter-spacing: -0.02em;
  color: var(--text);
  text-wrap: balance;
}

.vision-body {
  margin-top: 1.5rem;
  color: var(--muted);
  max-width: 48ch;
  text-wrap: pretty;
}

/* The commitment. Held apart from the analysis above it by a rule in the brand's own
   magenta, and set brighter and larger than the body copy it follows. */
.vision-mission {
  margin-top: 2.25rem;
  padding-left: 1.4rem;
  border-left: 2px solid var(--glitch-magenta);
  max-width: 46ch;
  font-size: 1.125rem;
  line-height: 1.62;
  color: var(--text);
  text-wrap: pretty;
}

/* <em> carries the emphasis for a screen reader; the cyan is what carries it on screen. */
.vision-mission em {
  font-style: normal;
  color: var(--glitch-cyan);
}

.vision-figure { position: relative; min-width: 0; }

/* Five tilted fragments scattered down the field, in the same magenta/cyan/silver the
   wordmark uses. Positions and sizes are measured from the reference art; the ~12° tilt is
   what stops them reading as a chart. Block sizing (not grid) so the percentage-positioned
   children always have a definite box to resolve against. */
.vision-signal {
  position: relative;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
  aspect-ratio: 11 / 12;
}

/* `translate` centres the chip on its coordinate and `rotate` sets the tilt, which leaves
   `transform` free for the jitter below — the three compose without restating each other. */
.vision-signal .vs-chip {
  position: absolute;
  width: 6.3%;
  aspect-ratio: 1;
  translate: -50% -50%;
}

.vs-chip--a { left: 54.1%; top: 24.3%; rotate:  12deg; background: var(--glitch-cyan); }
.vs-chip--b { left: 34.9%; top: 36.7%; rotate:  -9deg; background: var(--glitch-silver); }
.vs-chip--c { left: 49.8%; top: 47.1%; rotate:  10deg; background: var(--glitch-silver); }
.vs-chip--d { left: 34.9%; top: 53.0%; rotate: -13deg; background: var(--glitch-cyan); }
.vs-chip--e { left: 41.7%; top: 74.5%; rotate:  11deg; background: var(--glitch-magenta); }

/* One shared burst, staggered by negative delays so only one fragment slips at a time rather
   than the whole set twitching in unison. steps(1, end) keeps every change a hard cut — a
   glitch cuts, it never slides. Offsets are a percentage of each chip, so they scale with it. */
@media (prefers-reduced-motion: no-preference) {
  .vs-chip { animation: vs-chip-slip 6.5s steps(1, end) infinite; }
  .vs-chip--b { animation-delay: -1.3s; }
  .vs-chip--c { animation-delay: -2.6s; }
  .vs-chip--d { animation-delay: -3.9s; }
  .vs-chip--e { animation-delay: -5.2s; }
}

@keyframes vs-chip-slip {
  0%, 88%   { transform: none; }
  90%       { transform: translate(62%, -34%) rotate(16deg); }
  92%       { transform: translate(-40%, 22%) rotate(-12deg); }
  94%       { transform: translate(28%, 14%) rotate(7deg); }
  96%, 100% { transform: none; }
}

.section-note { margin-bottom: 2rem; font-size: var(--size-small); }

/* ---------- robotics senses: world map ---------- */

/* the map breaks out wider than the 680px text column for presence.
   Its width is capped to the viewport (below), so it never causes page scroll —
   don't clip it on the section, or the breakout edges (and China pins) get cut. */
.map {
  position: relative;
  width: min(100vw - 2rem, 1000px);
  margin: 0.5rem 0 3rem;
  margin-left: 50%;
  transform: translateX(-50%);
  aspect-ratio: 1000 / 383;
}

.map-dots {
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0.85;
}

/* a sense: a signal resolving out of the dark field at its real location */
.sense {
  position: absolute;
  width: 12px;
  height: 12px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--glitch-magenta);
  color: var(--glitch-magenta);
}

.sense-blue { background: var(--glitch-cyan); color: var(--glitch-cyan); }

/* the slow pulse — the signal breathing (matches the hero's motion budget) */
@media (prefers-reduced-motion: no-preference) {
  .sense::before {
    content: "";
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.45;
    animation: sense-pulse 3.2s ease-out infinite;
  }
}

@keyframes sense-pulse {
  0%   { transform: scale(0.6); opacity: 0.5; }
  70%  { transform: scale(2.6); opacity: 0; }
  100% { transform: scale(2.6); opacity: 0; }
}



/* ---------- open-source robot anatomy ---------- */

/* breaks out wider than the text column, like the map; body clip guards it */
.robot {
  width: min(100vw - 2rem, 900px);
  margin: 0.75rem 0 3.25rem;
  margin-left: 50%;
  transform: translateX(-50%);
}

.robot svg { width: 100%; height: auto; display: block; }

.rb-ink { fill: none; stroke: var(--text); stroke-width: 5.5; stroke-linecap: round; stroke-linejoin: round; }
.rb-fill { fill: var(--bg); stroke: var(--text); stroke-width: 5.5; stroke-linejoin: round; }
.rb-tooth { stroke: var(--text); stroke-width: 3; stroke-linecap: round; }
.rb-hatch { fill: none; stroke: var(--blue); stroke-width: 4; stroke-linecap: round; opacity: 0.85; }
.rb-nerve { fill: none; stroke: var(--purple); stroke-width: 2.2; stroke-dasharray: 1.5 9; stroke-linecap: round; opacity: 0.7; }
.rb-shadow { fill: #000; opacity: 0.38; }
.rb-leader { fill: none; stroke: var(--muted); stroke-width: 1.4; stroke-dasharray: 1 6; stroke-linecap: round; opacity: 0.65; }
.rb-dot { fill: var(--muted); }
.rb-cloud { fill: none; stroke: var(--muted); stroke-width: 2; stroke-dasharray: 6 6; opacity: 0.75; }
.rb-bub { fill: var(--bg); stroke: var(--muted); stroke-width: 2; opacity: 0.75; }

.rb-cat { fill: var(--muted); font-family: var(--font-body); font-size: 14px; font-weight: 500; letter-spacing: 2px; }
.rb-tool { fill: var(--purple); font-family: var(--font-display); font-size: 27px; }
.rb-desc { fill: var(--muted); font-family: var(--font-body); font-size: 14px; }
.rb-simcat { fill: var(--muted); font-family: var(--font-body); font-size: 12px; font-weight: 500; letter-spacing: 2px; }
.rb-simname { fill: var(--muted); font-family: var(--font-display); font-size: 19px; }

/* the tool names link to their GitHub repos: purple/muted → blue on hover, like site links */
.robot a { text-decoration: none; cursor: pointer; }
.robot a text { transition: fill 120ms ease; }
.robot a:hover .rb-tool,
.robot a:hover { fill: var(--blue); }

.repos-hint { font-size: var(--size-small); }

/* ---------- links ---------- */

a {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--purple);
  text-underline-offset: 3px;
  transition: text-decoration-color 120ms ease;
}

a:hover { text-decoration-color: var(--blue); }

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

/* the single orange moment on the page */
.contact-link {
  color: var(--orange);
  text-decoration-color: var(--orange);
  font-weight: 500;
}

.contact-link:hover { text-decoration-color: var(--text); }

/* ---------- footer ---------- */

footer {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: .75rem 2rem;
  max-width: 1120px;
  margin: 0 auto;
  padding: 6rem 24px 3rem;
  color: var(--muted);
  font-size: var(--size-small);
}

.x-link {
  display: inline-block;
  text-decoration: none;
  line-height: 0;
  margin-left: 0.6rem;
  vertical-align: -1px;
}

.x-link svg {
  width: 11px;
  height: 11px;
  fill: var(--muted);
  transition: fill 120ms ease;
}

.x-link:hover svg { fill: var(--text); }

/* ---------- blog ---------- */

/* for text the artwork already renders — kept in the DOM for screen readers and search */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.post-list { list-style: none; display: grid; gap: 1.5rem; }

.post-card {
  display: block;
  overflow: hidden;
  border: 1px solid rgba(242, 239, 233, 0.1);
  border-radius: 12px;
  text-decoration: none;
  transition: border-color 160ms ease;
}

.post-card:hover { border-color: rgba(180, 156, 255, 0.45); }

/* the card art sits flush to the border; the text block carries the padding */
.post-card-img { width: 100%; height: auto; display: block; }

.post-card-text { display: block; padding: 1.2rem 1.5rem 1.4rem; }

.post-card-meta { display: block; color: var(--muted); font-size: var(--size-small); }

.post-card-title {
  display: block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.45rem;
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 0.35rem 0 0.5rem;
  text-wrap: balance;
}

.post-card-dek { display: block; color: var(--muted); text-wrap: pretty; }

/* ---------- blog post ---------- */

/* sections inside an article sit closer together than the landing page's chapters */
.post section { padding: 2.75rem 0 0; }
.post-hero { padding-top: 5.25rem; }   /* clears the sticky nav */
.post .post-head { padding-top: 2.25rem; }

.post-meta { color: var(--muted); font-size: var(--size-small); }

.post-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.1rem, 5.5vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  margin: 0.6rem 0 0;
  text-wrap: balance;
}

.post-standfirst {
  margin-top: 1.1rem;
  color: var(--muted);
  font-size: 1.1875rem;
  max-width: 34ch;
  text-wrap: pretty;
}

/* The title drawn into the artwork holds up down to about 640px. Below that it's too
   small to carry the page, so the real <h1> — and the card's title — come back. */
@media (max-width: 640px) {
  .post-head .visually-hidden,
  .post-card .visually-hidden {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
  .post-head .post-title { margin: 0 0 0.85rem; }
  .post-card-title { margin-top: 0; }
}

/* breaks out wider than the 680px column, like the map; body clip guards it */
.post-figure {
  width: min(100vw - 2rem, 900px);
  margin: 0;
  margin-left: 50%;
  transform: translateX(-50%);
}

.post-figure img { width: 100%; height: auto; display: block; border-radius: 12px; }

/* the title card's own ground is #0b0a0b — the page's. No frame, no corners: it bleeds. */
.post-titlecard { border-radius: 0; }

/* stands in for artwork on a post that doesn't have any yet: the emergence motif as a slot */
.post-placeholder {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  border: 1px dashed rgba(242, 239, 233, 0.16);
  border-radius: 12px;
  background:
    radial-gradient(ellipse 50% 60% at 50% 50%,
      rgba(180, 156, 255, 0.16) 0%,
      rgba(143, 182, 255, 0.08) 45%,
      transparent 72%);
  overflow: hidden;
}

.ph-signal {
  position: absolute;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
    rgba(232, 240, 255, 0.9) 0%,
    rgba(152, 186, 255, 0.5) 32%,
    rgba(143, 182, 255, 0.14) 58%,
    transparent 74%);
  filter: blur(2px);
}

@media (prefers-reduced-motion: no-preference) {
  .ph-signal { animation: vs-emerge 6.5s ease-in-out infinite; }
}

.ph-label {
  position: relative;
  color: var(--muted);
  font-size: var(--size-small);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.post-body p { margin-top: 1.15rem; max-width: 62ch; text-wrap: pretty; }
.post-body p:first-child { margin-top: 0; }

.post-body h2 {
  font-size: 1.5rem;
  color: var(--text);
  margin: 1rem 0 0.5rem;
  text-wrap: balance;
}

.post-body a { color: var(--text); }

/* the two closing lines — the argument of the piece, set like a statement */
.post-close {
  margin-top: 2.25rem;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.4vw, 1.7rem);
  line-height: 1.32;
  text-wrap: balance;
}

/* ---------- post: interactive blocks ---------- */

/* every interactive sits in the same quiet card so they read as one system */
.post-interactive {
  padding-top: 2.75rem;
}

.interactive-label {
  font-size: var(--size-small);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-family: var(--font-body);
  color: var(--muted);
  margin-bottom: 1rem;
}

.stages,
.cra,
.question,
.exchange {
  border: 1px solid rgba(242, 239, 233, 0.1);
  border-radius: 12px;
  background: rgba(242, 239, 233, 0.018);
  padding: 1.25rem 1.4rem 1.4rem;
}

/* --- the four stages --- */

.stage-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}

.stage-tab,
.filter,
.q-opt {
  font: inherit;
  font-size: var(--size-small);
  color: var(--muted);
  background: transparent;
  border: 1px solid rgba(242, 239, 233, 0.16);
  border-radius: 999px;
  padding: 0.35rem 0.85rem;
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.stage-tab:hover,
.filter:hover,
.q-opt:hover { color: var(--text); border-color: rgba(242, 239, 233, 0.32); }

.stage-tab[aria-selected="true"],
.filter[aria-pressed="true"],
.q-opt[aria-pressed="true"] {
  color: var(--text);
  border-color: rgba(180, 156, 255, 0.55);
  background: rgba(180, 156, 255, 0.12);
}

.stage-tab:focus-visible,
.filter:focus-visible,
.q-opt:focus-visible { outline: 1.5px solid var(--text); outline-offset: 2px; }

/* without JS every panel is a plain stacked block; the tab bar stays hidden */
.stage-panel + .stage-panel { margin-top: 1.5rem; }
.stages.is-enhanced .stage-panel + .stage-panel { margin-top: 0; }

.stage-panel h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.2rem;
  margin-bottom: 0.5rem;
}

.stage-panel p { color: var(--muted); max-width: 56ch; }
.stage-panel p + p { margin-top: 0.75rem; }

/* the security question for this stage — the line that earns the interaction */
.stage-ask {
  border-left: 2px solid var(--purple);
  padding-left: 0.9rem;
  color: var(--text) !important;
}

.stage-ask-label {
  display: block;
  color: var(--muted);
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.15rem;
}

/* --- CRA penalty --- */

.cra-label {
  display: block;
  color: var(--muted);
  font-size: var(--size-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.cra-turnover {
  display: block;
  font-family: var(--font-display);
  font-size: 1.9rem;
  line-height: 1.2;
  margin-top: 0.15rem;
}

.cra-slider {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  margin: 1.1rem 0 1.4rem;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--purple), var(--blue));
  cursor: pointer;
}

.cra-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text);
  border: none;
  cursor: grab;
}

.cra-slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text);
  border: none;
  cursor: grab;
}

.cra-slider:focus-visible { outline: 1.5px solid var(--text); outline-offset: 6px; }

.cra-result {
  border-top: 1px solid rgba(242, 239, 233, 0.1);
  padding-top: 1.1rem;
}

.cra-fine {
  font-family: var(--font-display);
  font-size: 1.6rem;
  line-height: 1.2;
  /* the one orange moment on this page: the number that changes behaviour */
  color: var(--orange);
  transition: color 160ms ease;
}

.cra.is-capped .cra-fine { color: var(--text); }

.cra-fine-unit {
  font-family: var(--font-body);
  font-size: var(--size-small);
  color: var(--muted);
  letter-spacing: 0.02em;
}

.cra-basis { margin-top: 0.35rem; color: var(--muted); font-size: var(--size-small); }
.cra-note { margin-top: 1.1rem; font-size: 0.82rem; line-height: 1.55; }

/* --- disclosures --- */

.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.25rem; }

.disclosures { list-style: none; display: grid; gap: 0.6rem; }

.disclosure {
  border: 1px solid rgba(242, 239, 233, 0.1);
  border-radius: 10px;
  background: rgba(242, 239, 233, 0.018);
  transition: border-color 160ms ease;
}

.disclosure[open],
.disclosure:hover { border-color: rgba(180, 156, 255, 0.4); }

.disclosure summary {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.75rem;
  padding: 0.85rem 1rem;
  cursor: pointer;
  list-style: none;
}

.disclosure summary::-webkit-details-marker { display: none; }
.disclosure summary:focus-visible { outline: 1.5px solid var(--text); outline-offset: -2px; border-radius: 10px; }

.d-date {
  color: var(--muted);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  min-width: 5.5rem;
}

.d-name { flex: 1 1 14rem; font-weight: 500; }

/* the arrow doubles as the open/closed affordance */
.d-tag {
  color: var(--muted);
  font-size: 0.78rem;
  white-space: nowrap;
}

.d-tag::after { content: " ↓"; }
.disclosure[open] .d-tag::after { content: " ↑"; }

.d-body { padding: 0 1rem 1.1rem; }
.d-body p { color: var(--muted); max-width: 58ch; }
.d-body p + p { margin-top: 0.7rem; }

.d-source { font-size: var(--size-small); }
.d-source a { color: var(--muted); }

.disclosures-note { margin-top: 1.25rem; font-size: var(--size-small); max-width: 62ch; }

/* --- the San Francisco exchange --- */

.exchange { display: grid; gap: 0.75rem; padding: 1.75rem 1.4rem; }

.ex-line {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.2vw, 1.45rem);
  max-width: 30ch;
}

.ex-them { color: var(--muted); }
.ex-me { justify-self: end; text-align: right; color: var(--text); }

@media (prefers-reduced-motion: no-preference) {
  /* the pause between the lines is the joke; let them land one at a time */
  html.js:not(.no-motion) [data-animate] .ex-line {
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.5s ease, transform 0.5s ease;
  }
  html.js:not(.no-motion) [data-animate].in .ex-line { opacity: 1; transform: none; }
  html.js:not(.no-motion) [data-animate].in .ex-line:nth-child(2) { transition-delay: 0.5s; }
  html.js:not(.no-motion) [data-animate].in .ex-line:nth-child(3) { transition-delay: 1.15s; }
}

/* --- safety vs security --- */

.q-switch { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.25rem; }

.q-body { min-height: 5.5rem; display: grid; align-items: center; }

.q-text {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 2.4vw, 1.55rem);
  line-height: 1.3;
  max-width: 40ch;
  text-wrap: pretty;
}

/* without JS both questions read as a plain labelled pair — still the point, just
   without the beat of having to move to reach the second one */
.question:not(.is-enhanced) .q-switch { display: none; }
.question:not(.is-enhanced) .q-body { display: grid; gap: 1rem; }
.q-prefix { color: var(--muted); }
.question.is-enhanced .q-prefix { display: none; }

.footer-links { display: flex; gap: 1.5rem; margin: 0; margin-left: auto; }
.footer-links a { color: var(--muted); text-decoration: none; }
.footer-links a:hover, .footer-links a:focus-visible { color: var(--text); text-decoration: underline; text-underline-offset: 4px; }
