@import url("fonts.css");

/* ==========================================================================
   Siiv marketing site
   Design tokens follow the product palette: deep green ground, single
   bright green accent, off-white type.
   ========================================================================== */

:root {
  /* Ground and surfaces */
  --bg:            #071E0A;
  --surface:       #0D2E12;
  --surface-alt:   #0A2610;

  /* Accent */
  --accent:        #95E066;
  --accent-hi:     #A8E880;
  --accent-drop:   #528831;
  --accent-soft:   #C6F2A6;

  /* Secondary button */
  --btn2-bg:       #1C4510;
  --btn2-bg-hover: #1D7929;
  --btn2-drop:     #284616;

  /* Type */
  --fg:            #FAFAFA;
  --fg-bright:     #E8E8E8;
  --fg-muted:      #C7C7C7;
  --fg-soft:       rgba(250, 250, 250, 0.62);
  --fg-dim:        rgba(250, 250, 250, 0.60);
  --fg-faint:      rgba(250, 250, 250, 0.50);

  /* Caution (consumer-email prompt) */
  --warn:          #E5D049;
  --warn-line:     rgba(229, 208, 73, 0.45);
  --warn-bg:       rgba(229, 208, 73, 0.07);

  /* Kind glyphs for the step 01 graphic, used as mask images so one element
     carries both the shape and its colour. Stroke is black because a mask
     reads alpha, not hue; the colour comes from the class. */
  --glyph-email: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2015%2012%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%221.3%22%3E%3Crect%20x%3D%22.5%22%20y%3D%22.5%22%20width%3D%2214%22%20height%3D%2211%22%20rx%3D%221.5%22/%3E%3Cpath%20d%3D%22M1%201.5%207.5%206.5%2014%201.5%22/%3E%3C/svg%3E");
  --glyph-call: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M22%2016.92v3a2%202%200%200%201-2.18%202%2019.79%2019.79%200%200%201-8.63-3.07%2019.5%2019.5%200%200%201-6-6%2019.79%2019.79%200%200%201-3.07-8.67A2%202%200%200%201%204.11%202h3a2%202%200%200%201%202%201.72%2012.84%2012.84%200%200%200%20.7%202.81%202%202%200%200%201-.45%202.11L8.09%209.91a16%2016%200%200%200%206%206l1.27-1.27a2%202%200%200%201%202.11-.45%2012.84%2012.84%200%200%200%202.81.7A2%202%200%200%201%2022%2016.92z%22/%3E%3C/svg%3E");
  --glyph-file: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2028%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M14%202H6a2%202%200%200%200-2%202v20a2%202%200%200%200%202%202h12a2%202%200%200%200%202-2V8z%22/%3E%3Cpath%20d%3D%22M14%202v6h6%22/%3E%3C/svg%3E");
  --glyph-comment: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M21%2015a2%202%200%200%201-2%202H8l-5%204V5a2%202%200%200%201%202-2h14a2%202%200%200%201%202%202z%22/%3E%3C/svg%3E");
  --glyph-search: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%3E%3Ccircle%20cx%3D%2211%22%20cy%3D%2211%22%20r%3D%227%22/%3E%3Cpath%20d%3D%22M16.5%2016.5L21%2021%22/%3E%3C/svg%3E");

  /* Late (work monitor status) */
  --late:          #E08272;
  --late-line:     rgba(224, 130, 114, 0.42);
  --late-bg:       rgba(224, 130, 114, 0.14);

  /* Hairlines, in ascending strength */
  --line-1: rgba(149, 224, 102, 0.12);
  --line-2: rgba(149, 224, 102, 0.16);
  --line-3: rgba(149, 224, 102, 0.22);
  --line-4: rgba(149, 224, 102, 0.35);
  --line-n: rgba(250, 250, 250, 0.20);
  --line-n2: rgba(250, 250, 250, 0.24);

  /* Type families */
  --font-display: Archivo, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-body:    Inter, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Rhythm */
  --maxw:  1120px;
  --pad-x: clamp(20px, 5vw, 40px);
  --pad-y: clamp(56px, 7vw, 104px);
  --radius:   10px;
  --radius-lg: 12px;
  --radius-sm: 5px;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

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

html {
  scroll-behavior: smooth;
  /* Keep anchored sections clear of the sticky header. */
  scroll-padding-top: 84px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-soft); }

img { max-width: 100%; height: auto; display: block; }

::selection { background: var(--accent); color: var(--bg); }

input, textarea, button, select { font-family: inherit; font-size: inherit; }
input::placeholder, textarea::placeholder { color: rgba(250, 250, 250, 0.28); }

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

/* Screen-reader-only, but focusable (skip link). */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.skip-link:focus {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 100;
  width: auto; height: auto;
  clip: auto; clip-path: none;
  margin: 0;
  padding: 12px 18px;
  background: var(--accent);
  color: var(--bg);
  font: 600 14px/1 var(--font-body);
  border-radius: var(--radius-sm);
}

[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   Layout primitives
   -------------------------------------------------------------------------- */

.wrap { max-width: var(--maxw); margin-inline: auto; }

.section {
  padding: var(--pad-y) var(--pad-x);
  border-top: 1px solid var(--line-1);
}
.section--flush { border-top: 0; }
.section--tint { background: var(--surface-alt); }

/* Two-column: label on the left, prose on the right. Stacks on mobile. */
.split {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 4vw, 40px);
  align-items: start;
}
@media (min-width: 760px) {
  .split {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: clamp(28px, 5vw, 72px);
  }
}

/* --------------------------------------------------------------------------
   Typography
   -------------------------------------------------------------------------- */

.eyebrow {
  margin: 0 0 18px;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow--quiet { color: rgba(250, 250, 250, 0.58); }

/* A section marker, not a caption. At 11px in 58% white this reads as small
   print and gets skipped, which costs the reader the one word telling them
   what the next three columns are for. Full weight and a rule give it the
   job; the white keeps it from competing with the green question below. */
.eyebrow--section {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.22em;
  color: var(--fg);
}
.eyebrow--section::before {
  content: '';
  flex: 0 0 auto;
  width: 26px;
  height: 2px;
  background: var(--accent);
}

.h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(38px, 7vw, 76px);
  line-height: 0.99;
  letter-spacing: -0.038em;
  color: var(--fg);
  text-wrap: balance;
}
.h1--home { font-size: clamp(42px, 7.6vw, 84px); line-height: 0.97; max-width: 15ch; }

.h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(30px, 4.2vw, 48px);
  line-height: 1.04;
  letter-spacing: -0.032em;
  color: var(--fg);
  text-wrap: balance;
}

.h3 {
  margin: 0 0 10px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 21px;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--fg);
}

.lead {
  margin: clamp(24px, 3vw, 34px) 0 0;
  max-width: 56ch;
  font-size: clamp(17px, 1.5vw, 21px);
  line-height: 1.55;
  color: var(--fg-muted);
  text-wrap: pretty;
}

.prose {
  margin: 0;
  font-size: clamp(16px, 1.3vw, 19px);
  line-height: 1.66;
  color: var(--fg-muted);
  text-wrap: pretty;
}
.prose + .prose { margin-top: 20px; color: var(--fg); }

/* A run of lines that carry equal weight. The .prose + .prose lift above is
   for two-paragraph sections where the second is the punchline; across three
   lines of one story it reads as three different voices. Must stay directly
   after that rule: both are two-class selectors, so order decides. */
.prose-set { display: flex; flex-direction: column; gap: 20px; }
.prose-set .prose { margin: 0; color: var(--fg-muted); }

.copy {
  margin: 0;
  font-size: 15px;
  line-height: 1.62;
  color: var(--fg-muted);
  text-wrap: pretty;
}

.note {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--fg-dim);
}

.num {
  margin: 0 0 14px;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.18em;
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(7, 30, 10, 0.86);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-1);
}
.site-header__inner {
  max-width: 1180px;
  margin-inline: auto;
  padding: 14px var(--pad-x);
  display: flex;
  align-items: center;
  gap: 16px;
}
.site-header__logo { height: 30px; width: auto; margin-bottom: -9px; }
.site-header__cta { margin-left: auto; }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-block;
  border: 0;
  border-radius: var(--radius-sm);
  font: 600 15px/1 var(--font-body);
  padding: 15px 26px;
  cursor: pointer;
  text-align: center;
  transition: background-color 140ms ease, color 140ms ease, transform 140ms ease;
}
.btn--primary {
  background: var(--accent);
  color: var(--bg);
  box-shadow: 0 2px 0 var(--accent-drop);
}
.btn--primary:hover { background: var(--accent-hi); color: var(--bg); }
.btn--primary:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--accent-drop); }

.btn--secondary {
  background: var(--btn2-bg);
  color: var(--accent);
  box-shadow: 0 2px 0 var(--btn2-drop);
}
.btn--secondary:hover { background: var(--btn2-bg-hover); color: var(--fg); }
.btn--secondary:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--btn2-drop); }

.btn--sm { font-size: 13px; padding: 11px 16px; }
.btn--block { width: 100%; }

/* Understated inline link, used where the brief calls for a plain link
   rather than another button competing with the primary action. */
.link-quiet {
  display: inline-block;
  font: 500 13px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-soft);
  border-bottom: 1px solid var(--line-4);
  padding-bottom: 5px;
  transition: color 140ms ease, border-color 140ms ease;
}
.link-quiet:hover { color: var(--accent); border-color: var(--accent); }

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  padding: clamp(48px, 7vw, 84px) var(--pad-x) clamp(40px, 5vw, 64px);
  overflow: hidden;
}
.hero--tall { padding-top: clamp(64px, 10vw, 128px); padding-bottom: clamp(48px, 6vw, 88px); }
.hero--home { padding: clamp(72px, 12vw, 150px) var(--pad-x) clamp(56px, 8vw, 110px); }

.hero__glow {
  position: absolute;
  top: -190px;
  left: 50%;
  transform: translateX(-50%);
  width: min(900px, 140vw);
  height: 520px;
  background: radial-gradient(ellipse at center, rgba(149, 224, 102, 0.13), rgba(149, 224, 102, 0) 68%);
  pointer-events: none;
}
.hero__inner { position: relative; max-width: var(--maxw); margin-inline: auto; }

.hero__cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 3vw, 48px);
  align-items: end;
}
@media (min-width: 860px) {
  .hero__cols { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
}
.hero__sub {
  margin: 0;
  max-width: 52ch;
  font-size: clamp(16px, 1.25vw, 18px);
  line-height: 1.6;
  color: var(--fg-muted);
  text-wrap: pretty;
}
.hero__actions { margin-top: 24px; display: flex; flex-wrap: wrap; align-items: center; gap: 18px; }

/* --------------------------------------------------------------------------
   Cards: shared 1px-gap grid used by "What Siiv does" and "What it does today"
   -------------------------------------------------------------------------- */

/* Hairlines come from a border on each cell, pulled 1px outside and clipped
   by the container, rather than from a coloured gap. A gap would leave the
   container colour showing through whenever the item count does not fill the
   last row, which reads as a stray empty box. */
.tiles {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: 0;
  background: var(--bg);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  overflow: hidden;
}
.tiles > * {
  border-top: 1px solid var(--line-2);
  border-left: 1px solid var(--line-2);
  margin: -1px 0 0 -1px;
}
.tile { background: var(--bg); padding: clamp(22px, 2.6vw, 32px); }
.tile__num {
  margin: 0 0 16px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.18em;
  color: var(--accent);
}
.tile__title {
  margin: 0 0 12px;
  font: 600 20px/1.2 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--fg);
}

/* Shipped-feature rows. Container matches the row colour so a ragged last
   row is invisible. */
.tiles--rows {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  background: var(--surface);
}
.row {
  background: var(--surface);
  padding: 20px 22px;
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.row__mark {
  width: 8px;
  height: 8px;
  background: var(--accent);
  margin-top: 8px;
  flex: 0 0 auto;
}
.row__text {
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--fg-bright);
  text-wrap: pretty;
}

/* Numbered services list */
.tiles--numbered { grid-template-columns: 1fr; background: var(--surface); }
.row--numbered { padding: clamp(18px, 2.2vw, 26px); align-items: baseline; gap: 18px; }
.row__idx { font: 500 11px/1 var(--font-mono); color: var(--accent); flex: 0 0 auto; }
.row--numbered .row__text { font-size: clamp(15px, 1.3vw, 18px); line-height: 1.55; }

/* --------------------------------------------------------------------------
   Status banners: keeps shipped and planned visually separate
   -------------------------------------------------------------------------- */

.status {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(12px, 1.6vw, 18px);
  margin-bottom: clamp(26px, 3vw, 40px);
}
.badge {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 6px 10px;
  border-radius: 4px;
}
.badge--shipped { background: var(--accent); color: var(--bg); }
.badge--planned {
  color: var(--fg-dim);
  border: 1px dashed rgba(250, 250, 250, 0.32);
  padding: 5px 10px;
}
.h2--planned { color: rgba(250, 250, 250, 0.72); }

/* Planned features: dashed, dimmer, never reads as available */
.plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: clamp(14px, 1.6vw, 20px);
}
.plan {
  border: 1px dashed var(--line-n);
  border-radius: 8px;
  padding: 22px;
}
.plan__title {
  margin: 0 0 8px;
  font: 600 17px/1.28 var(--font-display);
  letter-spacing: -0.018em;
  color: rgba(250, 250, 250, 0.82);
}
.plan__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: rgba(250, 250, 250, 0.62);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   How it works
   -------------------------------------------------------------------------- */

.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
  gap: clamp(18px, 2vw, 26px);
}
.step { border-top: 1px solid var(--line-4); padding-top: 22px; }

/* Three full-width rows, each carrying a graphic. A variant rather than a
   change to .steps, which stays a multi-column grid for short text items. */
.steps--stacked { grid-template-columns: 1fr; gap: clamp(56px, 7vw, 96px); }
/* The query container sits on the step, not on the graphic: a container
   cannot style itself, and the graphics need to change their own height and
   converge distance at narrow widths. */
.steps--stacked .step { container-type: inline-size; }
.step__text {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 760px;
}
/* .h3 already carries margin-bottom; gap would double it. */
.step__text > .h3 { margin-bottom: 0; }

/* Optional AI note: dashed so it reads as optional, not a requirement */
.aside-optional {
  margin-top: 20px;
  border: 1px dashed var(--line-4);
  border-radius: 8px;
  padding: 18px;
  background: rgba(149, 224, 102, 0.04);
}
.aside-optional__label {
  margin: 0 0 10px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.aside-optional__text {
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: rgba(250, 250, 250, 0.72);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   The connection graphic (home). Coordination data and design data, tied
   together and kept as the project moves through time.
   -------------------------------------------------------------------------- */

.graphic {
  position: relative;
  margin-top: clamp(36px, 5vw, 60px);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: clamp(16px, 2.6vw, 34px);
  overflow: hidden;
}
.graphic__glow {
  position: absolute;
  top: -40%; left: 20%;
  width: 60%; height: 180%;
  background: radial-gradient(ellipse at center, rgba(149, 224, 102, 0.09), rgba(149, 224, 102, 0) 70%);
  pointer-events: none;
}
.graphic__inner { position: relative; }

.graphic__key {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(12px, 2vw, 26px);
  align-items: center;
  padding-bottom: clamp(16px, 2.2vw, 26px);
  border-bottom: 1px solid rgba(149, 224, 102, 0.14);
}
.key {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: 400 clamp(10px, 0.95vw, 11px)/1.3 var(--font-mono);
  letter-spacing: 0.04em;
  color: var(--fg-dim);
}
.key--coord { color: var(--accent); }
.key__swatch { width: 10px; height: 10px; border-radius: 2px; flex: 0 0 auto; }
.key__swatch--coord { background: var(--accent); }
.key__swatch--design { border: 1px solid rgba(250, 250, 250, 0.6); }
.key__caption {
  margin-left: auto;
  font: 400 clamp(10px, 0.95vw, 11px)/1.3 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

.timeline { padding-top: clamp(20px, 2.6vw, 30px); }

.tl {
  display: grid;
  /* Wide enough that "week 1" stays on one line at 390px. */
  grid-template-columns: clamp(58px, 7.5vw, 96px) clamp(22px, 2.4vw, 30px) minmax(0, 1fr);
  align-items: start;
}
.tl__when {
  margin: clamp(3px, 0.4vw, 5px) clamp(8px, 1.4vw, 16px) 0 0;
  padding-bottom: clamp(18px, 2.4vw, 26px);
  text-align: right;
  font: 400 clamp(10px, 0.95vw, 11px)/1.3 var(--font-mono);
  letter-spacing: 0.04em;
  color: var(--fg-dim);
}
.tl__rail {
  position: relative;
  display: flex;
  justify-content: center;
  align-self: stretch;
  min-height: 100%;
}
.tl__rail::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 1px;
  background: rgba(149, 224, 102, 0.28);
}
/* Last row: the rail stops at the node instead of running past it. */
.tl--last .tl__rail::before { bottom: auto; height: clamp(14px, 1.6vw, 20px); }

.tl__node {
  position: relative;
  width: clamp(10px, 1.1vw, 13px);
  height: clamp(10px, 1.1vw, 13px);
  border-radius: 2px;
  margin-top: clamp(4px, 0.5vw, 7px);
  box-shadow: 0 0 0 4px var(--surface);
  flex: 0 0 auto;
}
.tl__node--coord  { background: var(--accent); }
.tl__node--design { border: 1px solid rgba(250, 250, 250, 0.6); }
.tl__node--answer {
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--surface), 0 0 0 7px rgba(149, 224, 102, 0.35);
}

.tl__body {
  padding: 0 0 clamp(18px, 2.4vw, 26px) clamp(8px, 1.4vw, 16px);
  min-width: 0;
}
.tl--last .tl__body { padding-bottom: 0; }
.tl__event {
  margin: 0;
  font-size: clamp(13px, 1.15vw, 16px);
  line-height: 1.45;
  color: var(--fg-bright);
  text-wrap: pretty;
}
.tl__when--answer { color: var(--accent); }

.chips { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex;
  align-items: center;
  border-radius: 4px;
  padding: 5px 9px;
  font: 400 clamp(10px, 0.9vw, 11px)/1 var(--font-mono);
}
/* Solid outline = design data. Dashed green = coordination data. */
.chip--design { border: 1px solid rgba(250, 250, 250, 0.22); color: rgba(250, 250, 250, 0.55); }
.chip--coord  { border: 1px dashed var(--line-4); color: var(--accent); }

.answer {
  border: 1px solid var(--line-4);
  background: rgba(149, 224, 102, 0.07);
  border-radius: 8px;
  padding: clamp(14px, 1.8vw, 20px);
}
.answer__q {
  margin: 0;
  font-weight: 500;
  font-size: clamp(14px, 1.3vw, 18px);
  line-height: 1.4;
  color: var(--fg);
}
.answer__label {
  margin: 10px 0 12px;
  font: 400 clamp(10px, 0.95vw, 11px)/1.3 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   Animation slot (hero, holds beat 3 still then the full animation)
   -------------------------------------------------------------------------- */

.animation-slot {
  position: relative;
  margin-top: clamp(28px, 4vw, 44px);
  aspect-ratio: 2 / 1;
  max-width: 100%;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line-2);
  /* Makes cqw units inside resolve against this box, which is what scales
     the hero animation's 1000x500 design space. */
  container-type: size;
}
.animation-slot__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* --------------------------------------------------------------------------
   Form: let textarea span the full grid width
   -------------------------------------------------------------------------- */

[data-span-full] { grid-column: 1 / -1; }

/* --------------------------------------------------------------------------
   Panels (feature-interest, entry block, setup form, closing card)
   -------------------------------------------------------------------------- */

.panel {
  max-width: var(--maxw);
  margin-inline: auto;
  background: var(--surface);
  border: 1px solid rgba(149, 224, 102, 0.18);
  border-radius: var(--radius-lg);
  padding: clamp(22px, 3.4vw, 48px);
}
.panel--inline {
  margin-top: clamp(30px, 4vw, 48px);
  border-color: var(--line-2);
  border-radius: var(--radius);
  padding: clamp(22px, 3vw, 36px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(16px, 2.4vw, 30px);
  justify-content: space-between;
}
.panel--center { text-align: center; padding: clamp(26px, 4vw, 56px); }

.panel__ask {
  margin: 0;
  font: 600 clamp(19px, 2.2vw, 26px)/1.24 var(--font-display);
  letter-spacing: -0.024em;
  color: var(--fg);
}
.panel__grow { flex: 1 1 300px; }

/* Entry block on /product-web */
.entry {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 40px);
  align-items: start;
}
@media (min-width: 820px) {
  .entry { grid-template-columns: 1.15fr 1fr; gap: clamp(24px, 4vw, 56px); }
  .entry__side { border-left: 1px solid rgba(149, 224, 102, 0.18); padding-left: clamp(20px, 3vw, 36px); }
}
.entry__side-label {
  margin: 0 0 12px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

/* --------------------------------------------------------------------------
   Sandbox band
   -------------------------------------------------------------------------- */

.sandbox {
  position: relative;
  border-top: 1px solid rgba(149, 224, 102, 0.3);
  border-bottom: 1px solid rgba(149, 224, 102, 0.3);
  background: repeating-linear-gradient(135deg, rgba(149, 224, 102, 0.06) 0 2px, rgba(149, 224, 102, 0) 2px 12px);
  padding: clamp(34px, 4.4vw, 62px) var(--pad-x);
  overflow: hidden;
}
.sandbox__glow {
  position: absolute;
  top: -50%; left: 50%;
  transform: translateX(-50%);
  width: 70%; height: 200%;
  background: radial-gradient(ellipse at center, rgba(149, 224, 102, 0.1), rgba(149, 224, 102, 0) 70%);
  pointer-events: none;
}
.sandbox__inner {
  position: relative;
  max-width: var(--maxw);
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: clamp(20px, 4vw, 56px);
  align-items: center;
}
.sandbox__title {
  margin: 0;
  font: 600 clamp(26px, 3.6vw, 42px)/1.08 var(--font-display);
  letter-spacing: -0.032em;
  color: var(--fg);
}
.sandbox__text {
  margin: 0;
  max-width: 52ch;
  font-size: clamp(15px, 1.3vw, 18px);
  line-height: 1.6;
  color: var(--fg-muted);
  text-wrap: pretty;
}
.sandbox__link { margin-top: clamp(18px, 2.4vw, 26px); }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.field { display: block; }
.field__label {
  display: block;
  margin-bottom: 7px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.field__input,
.field__textarea {
  width: 100%;
  background: var(--bg);
  border: 1px solid rgba(149, 224, 102, 0.2);
  border-radius: var(--radius-sm);
  padding: 13px 14px;
  color: var(--fg);
  font: 400 15px/1.5 var(--font-body);
  transition: border-color 140ms ease;
}
.field__textarea { resize: vertical; min-height: 96px; }
.field__input:focus,
.field__textarea:focus { border-color: var(--accent); outline: none; }
.field__input:focus-visible,
.field__textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.field-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 14px;
}

/* A form is filled one field at a time, so it does not want the width the
   rest of the page uses. Held to roughly the measure of the prose above it;
   at the full 1120px the four inputs strung out across a single row and the
   note under the button was squeezed into a quarter-width column. */
.form-narrow { max-width: 640px; }

/* An explicit two columns, not auto-fit. auto-fit sizes tracks from a min
   width and fits as many as it can, which gives two bad results with four
   fields: at some widths it makes a fifth track the fields never fill, so
   they stop short of the form's right edge, and at others it makes three,
   stranding Role alone on a second row with a gap beside it. Two columns
   divide four fields evenly and always span the full width. */
.field-grid--form { grid-template-columns: 1fr 1fr; }

/* One column once half the form is too narrow to type a firm name into. */
@media (max-width: 559px) {
  .field-grid--form { grid-template-columns: 1fr; }
}
.field-stack { display: grid; gap: 14px; align-content: start; }

/* Radio options in the setup form */
.options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 14px;
}
.option {
  display: flex;
  gap: 13px;
  align-items: flex-start;
  background: var(--bg);
  border: 1px solid var(--line-3);
  border-radius: 8px;
  padding: 20px;
  cursor: pointer;
  transition: border-color 140ms ease;
}
.option:hover { border-color: var(--accent); }
.option:has(input:checked) { border-color: var(--accent); }
.option:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.option input { accent-color: var(--accent); width: 17px; height: 17px; margin: 2px 0 0; flex: 0 0 auto; }
.option__title {
  display: block;
  font: 600 16px/1.3 var(--font-display);
  letter-spacing: -0.018em;
  color: var(--fg);
}
.option__text {
  display: block;
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.58;
  color: var(--fg-muted);
}

/* Checkbox list in the feature-interest form */
.checks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 10px 22px;
}
.check { display: flex; gap: 11px; align-items: flex-start; cursor: pointer; }
.check input { accent-color: var(--accent); width: 17px; height: 17px; margin: 2px 0 0; flex: 0 0 auto; }
.check span { font-size: 14px; line-height: 1.5; color: var(--fg-muted); }

/* Inline prompt when a consumer email domain is typed */
.consumer-hint {
  margin-top: 16px;
  border: 1px solid var(--warn-line);
  background: var(--warn-bg);
  border-radius: 6px;
  padding: 14px;
}
.consumer-hint p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--warn);
}

/* Honeypot. Off-screen rather than display:none, which some bots skip.
   Hidden from assistive tech via aria-hidden on the wrapper. */
.hp {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-error {
  margin: 14px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--warn);
}

.form-foot {
  margin: 14px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: rgba(250, 250, 250, 0.58);
}

/* Confirmation replaces the form in place */
.done__label {
  margin: 0 0 10px;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}
.done__text {
  margin: 0;
  max-width: 34ch;
  font: 600 clamp(24px, 3.2vw, 36px)/1.16 var(--font-display);
  letter-spacing: -0.03em;
  color: var(--fg);
}
.done--inline {
  margin: 0;
  font: 600 15px/1.4 var(--font-body);
  color: var(--accent);
  flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   Form panels

   A panel holds a set of form fields. Without JS it sits in the page as an
   ordinary block, so every form is reachable and submittable. Once JS runs
   the panel is hidden and re-opened on demand as an overlay.
   -------------------------------------------------------------------------- */

.fpanel { margin-top: clamp(24px, 3vw, 36px); }

.fpanel__card {
  background: var(--surface);
  border: 1px solid rgba(149, 224, 102, 0.24);
  border-radius: var(--radius-lg);
  padding: clamp(22px, 3.2vw, 40px);
  text-align: left;
}

.fpanel__head { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 22px; }
.fpanel__kicker {
  margin: 0 0 8px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.fpanel__title {
  margin: 0;
  font: 600 clamp(22px, 2.8vw, 30px)/1.14 var(--font-display);
  letter-spacing: -0.028em;
  color: var(--fg);
}

/* The close control is meaningless until the panel is an overlay. */
.fpanel__close {
  display: none;
  margin-left: auto;
  background: transparent;
  border: 1px solid var(--line-n2);
  color: rgba(250, 250, 250, 0.7);
  width: 34px; height: 34px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font: 400 16px/1 var(--font-body);
  flex: 0 0 auto;
  transition: border-color 140ms ease, color 140ms ease;
}
.fpanel__close:hover { border-color: var(--accent); color: var(--accent); }

.fpanel.is-open {
  position: fixed;
  inset: 0;
  z-index: 80;
  margin: 0;
  background: rgba(3, 14, 5, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(16px, 4vw, 56px);
  overflow-y: auto;
}
.fpanel.is-open .fpanel__card {
  width: 100%;
  max-width: 600px;
  margin: auto;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
}
.fpanel--wide.is-open .fpanel__card { max-width: 680px; }
.fpanel.is-open .fpanel__close { display: block; }

body.is-locked { overflow: hidden; }

/* --------------------------------------------------------------------------
   Home routing buttons
   -------------------------------------------------------------------------- */

.start { max-width: 900px; margin-inline: auto; text-align: center; }
.start__h {
  margin: 0;
  font: 600 clamp(30px, 4.4vw, 52px)/1.05 var(--font-display);
  letter-spacing: -0.032em;
  color: var(--fg);
}
.start__pair {
  margin-top: clamp(30px, 4vw, 44px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap: 16px;
}
.start__btn {
  text-align: left;
  background: var(--accent);
  color: var(--bg);
  border: 0;
  border-radius: 8px;
  padding: clamp(22px, 2.6vw, 30px);
  cursor: pointer;
  box-shadow: 0 2px 0 var(--accent-drop);
  display: flex;
  flex-direction: column;
  gap: 10px;
  transition: background-color 140ms ease, transform 140ms ease;
}
.start__btn:hover { background: var(--accent-hi); }
.start__btn:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--accent-drop); }
.start__btn-main {
  font: 600 clamp(19px, 2vw, 24px)/1.2 var(--font-display);
  letter-spacing: -0.02em;
}
.start__btn-sub {
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.65;
}

/* --------------------------------------------------------------------------
   Services: bios and examples
   -------------------------------------------------------------------------- */

.bios {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: clamp(16px, 2vw, 24px);
}
.bio {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: clamp(22px, 2.6vw, 30px);
}
.bio__name {
  margin: 0 0 6px;
  font: 600 19px/1.25 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--fg);
}
.bio__cred {
  margin: 0 0 16px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.bio__text { margin: 0; font-size: 15px; line-height: 1.62; color: var(--fg-muted); text-wrap: pretty; }

/* Unwritten bio slot. Remove the card entirely once the copy lands. */
.bio--todo { background: var(--surface-alt); border: 1px dashed rgba(250, 250, 250, 0.22); }
.bio--todo .bio__name { color: rgba(250, 250, 250, 0.8); }
.bio--todo .bio__cred { color: var(--fg-dim); }
.bio--todo .bio__text { font: 400 14px/1.62 var(--font-mono); color: rgba(250, 250, 250, 0.55); }

.examples { display: grid; gap: clamp(16px, 2vw, 22px); }
.example {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: clamp(22px, 3vw, 38px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: clamp(20px, 3vw, 44px);
}
.example__kicker {
  margin: 0 0 14px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.example__title {
  margin: 0;
  max-width: 20ch;
  font: 600 clamp(21px, 2.4vw, 28px)/1.18 var(--font-display);
  letter-spacing: -0.026em;
  color: var(--fg);
}
.example__stat {
  margin: 22px 0 0;
  font: 500 clamp(26px, 3vw, 38px)/1 var(--font-display);
  letter-spacing: -0.03em;
  color: var(--accent);
}
.example__stat-note { margin: 8px 0 0; font-size: 13px; line-height: 1.5; color: var(--fg-dim); }
.example__body { margin: 0; font-size: 15px; line-height: 1.66; color: var(--fg-muted); text-wrap: pretty; }

/* --------------------------------------------------------------------------
   Notice bar (post-submit confirmation on the destination page)
   -------------------------------------------------------------------------- */

.notice { background: var(--accent); color: var(--bg); }

/* Without JS the form endpoint redirects to #notice, which is the only way
   the confirmation can be shown on a static page. Beats [hidden] on
   specificity, so the bar appears. */
#notice:target { display: block !important; }
.notice__inner {
  max-width: 1180px;
  margin-inline: auto;
  padding: 14px var(--pad-x);
  display: flex;
  align-items: center;
  gap: 12px;
}
.notice__dot { width: 7px; height: 7px; background: var(--bg); border-radius: 50%; flex: 0 0 auto; }
.notice__text { margin: 0; font: 600 15px/1.4 var(--font-body); }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line-1);
  padding: clamp(40px, 5vw, 64px) var(--pad-x);
}
.site-footer__inner {
  max-width: var(--maxw);
  margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: clamp(24px, 4vw, 48px);
  align-items: start;
}
/* --------------------------------------------------------------------------
   Simplified footer (wordmark + email, nothing else)

   Must stay below .site-footer__inner: both are single-class selectors, so
   the later one wins. Sitting above it, this whole block was dead and the
   simple footer was silently rendering as the base grid.
   -------------------------------------------------------------------------- */

.site-footer--simple { padding: clamp(32px, 4vw, 48px) var(--pad-x); }

/* Full bleed, unlike .wrap and the main footer: the wordmark goes hard left
   and the address hard right, held off the edges only by the footer's own
   padding. This deliberately breaks alignment with the 1120px content
   column above it. */
.site-footer__inner--simple {
  max-width: none;
  margin-inline: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.site-footer__logo { height: 26px; width: auto; opacity: 0.9; }
.site-footer__tag {
  margin: 18px 0 0;
  max-width: 32ch;
  font-size: 14px;
  line-height: 1.6;
  color: var(--fg-dim);
}
.site-footer__col { display: flex; flex-direction: column; gap: 12px; }
.site-footer__col p { margin: 0; font-size: 14px; line-height: 1; color: var(--fg-dim); }
.site-footer__legal {
  font: 500 10px/1 var(--font-mono) !important;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-faint) !important;
}

/* --------------------------------------------------------------------------
   Utilities

   Small and deliberately few. These exist so the pages carry no inline style
   attributes, which lets the Content-Security-Policy stay strict.
   -------------------------------------------------------------------------- */

.mt-8  { margin-top: 8px; }
.mt-14 { margin-top: 14px; }
.mt-16 { margin-top: 16px; }
.mt-22 { margin-top: 22px; }
.mt-24 { margin-top: 24px; }
.mt-block { margin-top: clamp(30px, 4vw, 52px); }
.mt-cta   { margin-top: clamp(28px, 4vw, 44px); }

.mb-0 { margin-bottom: 0; }
.mb-head      { margin-bottom: clamp(28px, 3.8vw, 48px); }
.mb-form-head { margin-bottom: clamp(22px, 3vw, 32px); }

.mi-auto { margin-inline: auto; }
.mi-0    { margin-inline: 0; }

.mw-18 { max-width: 18ch; }
.mw-22 { max-width: 22ch; }
.mw-24 { max-width: 24ch; }
.mw-26 { max-width: 26ch; }
/* Keeps a citation chip on the same line as the word it cites, so a wrap
   cannot strand it and its full stop at the start of the next line. */
.nb { white-space: nowrap; }
.mw-60 { max-width: 60ch; }
.mw-66 { max-width: 66ch; }

.shrink-0 { flex: 0 0 auto; }

.section--tight-top { padding-top: clamp(48px, 7vw, 80px); }
.section--no-top { padding-top: 0; }

/* The services problem statement is one paragraph carrying the section. */
.prose--statement {
  font-size: clamp(17px, 1.5vw, 21px);
  line-height: 1.58;
  color: var(--fg-bright);
}

/* Setup form: details on the left, the open question on the right, with the
   textarea stretching to match. */
.setup-grid {
  margin-top: clamp(24px, 3vw, 34px);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
}
.field-grid--tight { grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr)); }
.field--fill { display: flex; flex-direction: column; }
.field__textarea--fill { flex: 1; min-height: 150px; }

/* --------------------------------------------------------------------------
   Motion
   -------------------------------------------------------------------------- */

@keyframes softpulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }

[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 700ms cubic-bezier(0.22, 1, 0.36, 1),
              transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
}
[data-reveal].is-revealed { opacity: 1; transform: none; }
/* No JS: never leave content invisible. */
.no-js [data-reveal] { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  [data-reveal] { opacity: 1; transform: none; }

  /* Scoped to .sg on purpose. The staged graphics would otherwise keep their
     staggers and play as a staircase of instant jumps. This must NOT be
     global: the hero animation phases its loops with negative animation-delay
     (-4s, -8s), and zeroing those collapses all three tiles onto one beat. */
  .sg, .sg *, .sg *::before, .sg *::after {
    transition-delay: 0ms !important;
    animation-delay: 0ms !important;
  }
}

/* --------------------------------------------------------------------------
   Hero animation

   A 1000x500 design space rendered with container-query units, so 1 design
   pixel is 0.1cqw and the whole scene scales with the slot. That means no
   ResizeObserver and no JavaScript: it works before the page has finished
   loading and with scripting off entirely.

   The travelling dots live inside the SVG rather than using offset-path,
   because path() coordinates are absolute pixels and would not scale.
   -------------------------------------------------------------------------- */

.ha {
  position: absolute;
  inset: 0;
  /* The stacking context belongs at the stage, not on each tile. Painting
     order inside it puts the z-index:-1 children (the arriving cards, the
     paper edges) before the positioned tiles, so a card slides in behind
     the stack. Putting this on .ha__src instead paints the card above that
     tile's own background, which reads as the card landing on top of it.
     The design reference got this context free from a transform on its
     stage; container units replaced that transform, so ask for it here. */
  isolation: isolate;
  --ha-dur: 26s;
  --ha-cycle: 2.6s;
  --ha-ease: cubic-bezier(0.22, 1, 0.36, 1);
  font-family: var(--font-body);
}

.ha__glow {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 46% 70% at 50% 50%, rgba(149, 224, 102, 0.10), rgba(149, 224, 102, 0) 70%);
  pointer-events: none;
}

.ha__label {
  position: absolute;
  top: 1cqw;
  font: 500 1cqw/1 var(--font-mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ha__label--in  { left: 4cqw;  color: rgba(250, 250, 250, 0.5); }
.ha__label--out { left: 47cqw; color: var(--accent); }

/* The connector wires and the dots that travel along them. */
.ha__wires { position: absolute; inset: 0; width: 100%; height: 100%; }
.ha__wire { stroke: rgba(149, 224, 102, 0.20); stroke-width: 1.5; fill: none; }
.ha__dot { fill: var(--accent); filter: drop-shadow(0 0 6px rgba(149, 224, 102, 0.75)); }

/* ---- Left column: the three places work is discussed ---- */

.ha__src {
  position: absolute;
  left: 4cqw;
  width: 19cqw;
  height: 8.4cqw;
  border: 1px solid var(--line-2);
  border-radius: 0.8cqw;
  background: var(--surface-alt);
  display: flex;
  align-items: center;
  gap: 1.4cqw;
  padding: 0 1.8cqw;
  animation: ha-tile var(--ha-dur) ease-in-out infinite;
}
.ha__src--email    { top: 7.6cqw; }
.ha__src--meetings { top: 20.8cqw; animation-delay: -4s; }
.ha__src--notes    { top: 34cqw;   animation-delay: -8s; }

/* The item sliding in from off-stage and landing on the stack. */
.ha__arrive {
  position: absolute;
  left: 0;
  top: 0;
  width: 19cqw;
  height: 8.4cqw;
  border-radius: 0.8cqw;
  background: #0D3315;
  border: 1px solid rgba(149, 224, 102, 0.34);
  z-index: -1;
  display: flex;
  align-items: center;
  gap: 1.4cqw;
  padding: 0 1.8cqw;
  animation: ha-arrive var(--ha-cycle) cubic-bezier(0.3, 0.9, 0.3, 1) infinite;
}
.ha__src--email    .ha__arrive { animation-delay: -0.2s; }
.ha__src--meetings .ha__arrive { animation-delay: -1.5s; }
.ha__src--notes    .ha__arrive { animation-delay: -0.9s; }

.ha__arrive-chip {
  width: 2.2cqw;
  height: 2.2cqw;
  border-radius: 0.4cqw;
  background: rgba(149, 224, 102, 0.22);
  flex: 0 0 auto;
}
.ha__arrive-lines { flex: 1 1 auto; display: flex; flex-direction: column; gap: 0.7cqw; }
.ha__arrive-line {
  height: 0.7cqw;
  width: 78%;
  border-radius: 0.3cqw;
  background: rgba(250, 250, 250, 0.20);
}
.ha__arrive-line--short { height: 0.6cqw; width: 52%; background: rgba(250, 250, 250, 0.11); }

/* Paper edges peeking out below, suggesting a pile. */
.ha__stack {
  position: absolute;
  background: var(--surface-alt);
  border-top: 0;
  z-index: -1;
}
.ha__stack--1 {
  left: 0.9cqw; right: 0.9cqw; top: 100%;
  height: 0.7cqw;
  border: 1px solid rgba(149, 224, 102, 0.14);
  border-top: 0;
  border-radius: 0 0 0.7cqw 0.7cqw;
}
.ha__stack--2 {
  left: 2cqw; right: 2cqw; top: calc(100% + 0.7cqw);
  height: 0.6cqw;
  border: 1px solid rgba(149, 224, 102, 0.10);
  border-top: 0;
  border-radius: 0 0 0.6cqw 0.6cqw;
}

.ha__src-icon {
  width: 2.2cqw;
  height: 2.2cqw;
  flex: 0 0 auto;
  stroke: var(--fg);
  stroke-width: 1.4;
  fill: none;
  opacity: 0.82;
}
.ha__src-name {
  font: 600 1.5cqw/1.2 var(--font-display);
  letter-spacing: -0.01em;
  color: var(--fg);
}
.ha__src-app {
  margin-top: 0.4cqw;
  font: 400 1cqw/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.5);
}

/* Running totals, pinned to the corner of each tile. */
.ha__badge {
  position: absolute;
  top: -1.3cqw;
  right: -1.3cqw;
  height: 3cqw;
  padding: 0 1.1cqw;
  border-radius: 1.5cqw;
  display: flex;
  align-items: center;
  gap: 0.7cqw;
  box-shadow: 0 0 0 0.4cqw var(--surface);
}
.ha__badge--solid {
  min-width: 4.6cqw;
  justify-content: center;
  background: var(--accent);
  color: var(--bg);
  box-shadow: 0 0 0 0.4cqw var(--surface), 0 0.4cqw 1.4cqw rgba(149, 224, 102, 0.35);
}
.ha__badge--outline {
  background: var(--surface);
  border: 1px solid rgba(149, 224, 102, 0.45);
}
.ha__badge-num {
  font: 700 1.4cqw/1 var(--font-display);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.ha__badge--solid .ha__badge-num { font-size: 1.6cqw; letter-spacing: -0.02em; color: inherit; }
.ha__badge-unit {
  font: 500 1cqw/1 var(--font-mono);
  letter-spacing: 0.08em;
  color: rgba(149, 224, 102, 0.7);
}
.ha__live {
  width: 0.6cqw;
  height: 0.6cqw;
  border-radius: 50%;
  background: var(--accent);
  animation: ha-blink var(--ha-cycle) ease-in-out infinite;
}

/* ---- The point everything converges on ---- */

.ha__node { position: absolute; left: 38cqw; top: 25cqw; width: 0; height: 0; }
.ha__node-core {
  position: absolute;
  left: 0; top: 0;
  width: 2.6cqw;
  height: 2.6cqw;
  margin: -1.3cqw 0 0 -1.3cqw;
  border-radius: 0.3cqw;
  background: var(--accent);
  box-shadow: 0 0 2.4cqw rgba(149, 224, 102, 0.5);
  animation: ha-nodepulse var(--ha-cycle) ease-in-out infinite;
}
.ha__node-ring {
  position: absolute;
  left: 0; top: 0;
  width: 4.6cqw;
  height: 4.6cqw;
  border-radius: 50%;
  border: 1px solid var(--accent);
  animation: ha-ring var(--ha-cycle) ease-out infinite;
}

/* ---- Right column: one feed, grouped by topic ---- */

.ha__feed { position: absolute; left: 47cqw; top: 4.8cqw; width: 49cqw; }

.ha__card {
  height: 9.6cqw;
  margin-bottom: 1.2cqw;
  border: 1px solid rgba(149, 224, 102, 0.18);
  border-radius: 0.8cqw;
  background: var(--surface-alt);
  padding: 0 2cqw;
  display: flex;
  align-items: center;
  gap: 1.6cqw;
  /* backwards, or the delayed cards sit in their base state until their turn
     comes: fully drawn on load, then the animation starts at 0% and fades
     them in over the copy already showing. The delay has to hold the first
     frame, not the finished one. */
  animation: ha-card var(--ha-dur) var(--ha-ease) infinite backwards;
}
.ha__card:last-child { margin-bottom: 0; }
.ha__card--2 { animation-delay: 1.7s; }
.ha__card--3 { animation-delay: 3.4s; }
.ha__card--4 { animation-delay: 5.1s; }

.ha__card-body { flex: 1 1 auto; min-width: 0; }
.ha__card-title {
  font: 600 1.7cqw/1.25 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--fg);
}

.ha__chips { margin-top: 0.9cqw; display: flex; align-items: center; gap: 0.7cqw; }
.ha__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.6cqw;
  padding: 0.4cqw 0.9cqw;
  border-radius: 0.4cqw;
  background: rgba(250, 250, 250, 0.05);
  border: 1px solid rgba(250, 250, 250, 0.10);
  color: rgba(250, 250, 250, 0.66);
}
.ha__chip-icon {
  width: 1.2cqw;
  height: 1.2cqw;
  flex: 0 0 auto;
  stroke: currentColor;
  stroke-width: 1.7;
  fill: none;
}
.ha__chip-num { font: 500 1.1cqw/1 var(--font-mono); letter-spacing: 0.04em; }

.ha__flag {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 0.7cqw;
  padding: 0.6cqw 1cqw;
  border-radius: 0.4cqw;
  border: 1px solid rgba(149, 224, 102, 0.45);
  background: rgba(149, 224, 102, 0.09);
  /* Same as the cards: the flag on card 3 is delayed, so without this it is
     drawn in full from load and then re-animates. */
  animation: ha-flag var(--ha-dur) var(--ha-ease) infinite backwards;
}
.ha__flag--due { border-color: var(--warn-line); background: var(--warn-bg); }
.ha__card--3 .ha__flag { animation-delay: 3.4s; }

.ha__flag-dot { width: 0.6cqw; height: 0.6cqw; border-radius: 50%; background: var(--accent); }
.ha__flag--due .ha__flag-dot { background: var(--warn); }
.ha__flag-text {
  font: 500 1cqw/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
}
.ha__flag--due .ha__flag-text { color: var(--warn); }

/* ---- Motion ---- */

@keyframes ha-tile {
  0%, 100% { border-color: rgba(149, 224, 102, 0.16); }
  50%      { border-color: rgba(149, 224, 102, 0.42); }
}
@keyframes ha-arrive {
  0%   { transform: translate(-25cqw, 2.6cqw) rotate(-7deg) scale(0.94); opacity: 0; }
  16%  { opacity: 1; }
  62%  { transform: translate(0, 0) rotate(0deg) scale(1); opacity: 1; }
  76%, 100% { transform: translate(0, 0) rotate(0deg) scale(1); opacity: 0; }
}
@keyframes ha-card {
  0%   { opacity: 0; transform: translateY(1.4cqw) scale(0.985); }
  2%   { opacity: 1; transform: none; }
  88%  { opacity: 1; transform: none; }
  92%, 100% { opacity: 0; transform: translateY(-0.6cqw) scale(0.99); }
}
@keyframes ha-flag {
  0%, 22%  { opacity: 0; transform: translateX(0.8cqw); }
  25%      { opacity: 1; transform: none; }
  88%      { opacity: 1; transform: none; }
  92%, 100% { opacity: 0; transform: none; }
}
@keyframes ha-ring {
  0%   { transform: translate(-50%, -50%) scale(0.6); opacity: 0.55; }
  100% { transform: translate(-50%, -50%) scale(2.4); opacity: 0; }
}
@keyframes ha-nodepulse {
  0%, 100% { transform: rotate(45deg) scale(1); }
  50%      { transform: rotate(45deg) scale(1.14); }
}
@keyframes ha-blink {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

/* Reduced motion: hold the scene still and drop the travelling dots, which
   are driven by SMIL and so are not covered by the animation reset above. */
@media (prefers-reduced-motion: reduce) {
  /* Step 01 holds its end state: the pile already emptied, the rows already
     landed. The global block below zeroes durations, but these carry delays
     and a start opacity of 0, so they need saying explicitly. */
  /* Scoped to .sg--stream so these outrank the container-query rules for
     .sgs, which sit later in the file and would otherwise win on order. */
  .sg--stream .sgs, .sg--stream .sgs__in, .sg--stream .sgs__card,
  .sg--stream .sgs__row--in, .sg--stream .sgs__row--in .sgs__dot { animation: none; }
  /* Forced, unlike the rest of this block. The settle animation is declared
     later and with higher specificity (.sg[data-s1] .sgs), and the global
     reset above only zeroes its duration, so it still fills to its final
     translateX(-22%). Against the 40/56 grid that centres the threads;
     against the 1fr column here it drags them off the left edge. */
  .sg--stream .sgs {
    grid-template-columns: 1fr;
    gap: 0;
    animation: none !important;
    transform: none !important;
  }
  .sg--stream .sgs__in { display: none; }
  .sg--stream .sgs__row--in { opacity: 1; transform: none; }
  .sg--stream .sgs__row--in .sgs__dot { opacity: 1; }

  .ha__dots { display: none; }
  .ha__card, .ha__flag, .ha__arrive { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   Step graphics ("What Siiv does")

   Three abstract graphics that animate once as they scroll into view.

   Stages are cumulative attributes on the graphic root: data-s1, data-s2,
   data-s3, added by site.js and never removed. Because they are monotonic
   and the rules below are ordered 1 -> 2 -> 3, applying all three at once
   composites to exactly the final state. That is what makes the no-JS and
   reduced-motion fallbacks free: `.no-js .sg` is appended to every stage
   selector, so those users land on the finished picture with no duplicated
   ruleset.

   Idle is the base state with no attribute in the markup, so nothing ever
   transitions backwards on load.

   Staggers ride on an inherited --i index, multiplied differently per stage.
   ========================================================================== */

.sg {
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: clamp(18px, 2.2vw, 28px);
  margin-top: 26px;
}

/* The label's line box is load-bearing: step 03's connector is offset by it. */
.sg__label {
  margin: 0;
  font: 500 11px/16px var(--font-mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.50);
}

.sg__meta {
  font: 400 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.07em;
  color: rgba(250, 250, 250, 0.66);
}

/* --------------------------------------------------------------------------
   01 — unsorted work arriving on the thread it belongs to

   A simplified, reflowing take on the handoff's fixed 1120x700 composition.
   That version scaled as a single unit, which put its 9px row text at about
   3px on a phone. Here the two halves are a grid that stacks, the rows sit
   in normal flow inside their thread, and type stays at a fixed legible
   size at every width. Nothing is positioned against a fixed frame.

   What is kept: the pile of unsorted material emptying out, rows landing in
   chronological order on a rail, the fade gradient that says the list keeps
   going, the nine month gap that proves the grouping held, and the kind of
   each item carried by its glyph colour.

   What is dropped: the literal twelve-card crossing flight and the closing
   slide. The pile empties as the rows swoop in on staggered arcs, so the
   eye still links them, without geometry that only works at one size.
   -------------------------------------------------------------------------- */

/* A fixed frame. Nothing inside it resizes at any point in the animation:
   the columns are fixed fractions and the settle is a translate, not a
   re-layout. The last thread is clipped by the bottom edge on purpose, so
   the list reads as continuing past it. */
/* Tall enough that the third thread shows its name and its Grouped by chip
   and is then cut mid-row, so it reads as continuing past the edge rather
   than as a stray sliver. Each thread carries a chip now, which is taller
   than the line it replaced; that and the original justification lines are
   what took this from 420 to 524. */
.sg--stream { height: 524px; overflow: hidden; }

.sgs {
  display: grid;
  grid-template-columns: 1fr;
  align-items: start;
}
/* 40 + 4 + 56 = 100, so the tracks never re-solve. The settle then shifts
   the whole grid left by half the pile column plus its gap, which lands the
   thread column on the centre line with even margins. */
@container (min-width: 660px) {
  .sgs { grid-template-columns: 40% 56%; gap: 4%; }
  /* The pile is 211px of content in a 206px box, so the fifth card loses
     its bottom edge and then turns up in the threads looking like it was
     never queued. The hidden overflow below is only there to let the track
     collapse on the stacked layout, where the pile is display:none anyway,
     so it can be visible wherever the pile is actually drawn. */
  .sg--stream .sgs__in { overflow: visible; }
}
/* No room for a pile beside the threads at this width, so the threads take
   the frame and the arriving rows carry the idea on their own. */
@container (max-width: 659px) {
  /* Scoped to .sg--stream so it outranks the .sgs__in, .sgs__out base rule
     below, which sets display: flex at the same specificity and would
     otherwise win on source order. */
  .sg--stream .sgs__in { display: none; }
}

.sgs__in, .sgs__out { min-width: 0; display: flex; flex-direction: column; gap: 12px; }
/* A grid item defaults to min-height: auto, which would hold the 0fr track
   open when the pile collapses on the stacked layout. */
.sgs__in { min-height: 0; overflow: hidden; }

/* ---- The pile of unsorted material ---- */

.sgs__pile { position: relative; display: flex; flex-direction: column; gap: 7px; }

.sgs__card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  height: 30px;
  border-radius: 7px;
  background: rgba(250, 250, 250, 0.05);
  border: 1px solid rgba(250, 250, 250, 0.14);
  transform: rotate(var(--rot));
}
.sgs__card--1 { --rot: -1.3deg; --delay: 0.15s; }
.sgs__card--2 { --rot:  1.1deg; --delay: 0.45s; }
.sgs__card--3 { --rot:  0.9deg; --delay: 0.75s; }
.sgs__card--4 { --rot: -1.5deg; --delay: 1.05s; }
.sgs__card--5 { --rot:  1.4deg; --delay: 1.35s; }

.sgs__card-title {
  font: 500 11px/1.3 var(--font-body);
  color: rgba(250, 250, 250, 0.88);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- Threads ---- */

.sgs__thread {
  border-radius: var(--radius);
  border: 1px solid rgba(149, 224, 102, 0.18);
  background: rgba(149, 224, 102, 0.03);
  padding: 9px 12px 11px;
}
/* The gradient that says the list keeps going and dies out. It reaches the
   container, its name, its rail, its rows and its dots by inheritance. */
.sgs__thread--lead {
  opacity: 1;
  border-color: rgba(149, 224, 102, 0.32);
  background: rgba(149, 224, 102, 0.055);
}
.sgs__thread--mid { opacity: 0.62; --i: 1; }
.sgs__thread--far { opacity: 0.32; --i: 2; }
.sgs__thread + .sgs__thread { margin-top: 10px; }

/* Why these rows are one thread, as a chip rather than a line of trace grey,
   which read as metadata and got skipped. The label is the same on all three
   so the eye learns it once and then only reads what changes; the thing that
   changes carries the accent, because the grouping is Siiv's inference and
   nothing else in the card is. */
.sgs__why {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  max-width: 100%;
  margin: 6px 0 9px;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid rgba(149, 224, 102, 0.28);
  background: rgba(149, 224, 102, 0.09);
  /* Drifts in once the rows have finished landing, so it reads as the
     conclusion of the consolidation rather than part of it. */
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.2, .8, .3, 1);
  transition-delay: calc(var(--i, 0) * 150ms);
}
.sg[data-s2] .sgs__why, .no-js .sgs__why { opacity: 1; transform: none; }

.sgs__why-label {
  flex: 0 0 auto;
  font: 400 8.5px/1.5 var(--font-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.45);
}
.sgs__why-val {
  min-width: 0;
  font: 600 11.5px/1.5 var(--font-body);
  letter-spacing: 0.01em;
  color: var(--accent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sgs__thread-name {
  margin: 0;
  font: 600 12.5px/1.2 var(--font-display);
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Rows sit in flow; the rail runs behind them and the dots sit on it. */
.sgs__rows { position: relative; padding-left: 22px; display: flex; flex-direction: column; gap: 4px; }
.sgs__rail {
  position: absolute;
  left: 4px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: rgba(149, 224, 102, 0.3);
}

.sgs__row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 7px;
  height: 24px;
  padding: 0 9px;
  border-radius: 6px;
  background: rgba(250, 250, 250, 0.05);
  border: 1px solid rgba(250, 250, 250, 0.14);
}
.sgs__row-title {
  font: 500 11px/1.3 var(--font-body);
  color: rgba(250, 250, 250, 0.88);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sgs__dot {
  position: absolute;
  left: -22px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-radius: 999px;
  background: var(--accent);
}

/* Historical. Proof the grouping held across a long silence, so it is
   present from the first frame and never animates. */
.sgs__gap {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 1px 0;
  height: 14px;
  opacity: 0.5;
  font: 500 8.5px/1 var(--font-mono);
  letter-spacing: 0.1em;
  color: rgba(250, 250, 250, 0.5);
  white-space: nowrap;
}
.sgs__gap-rule { width: 14px; height: 1px; background: rgba(250, 250, 250, 0.2); flex: 0 0 auto; }
.sgs__gap-rule--fill { flex: 1 1 auto; width: auto; }

/* ---- Kind glyphs. The only thing that differs between items. ---- */

.sgs__glyph {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}
.sgs__glyph--email {
  color: var(--accent);
  -webkit-mask-image: var(--glyph-email);
  mask-image: var(--glyph-email);
}
.sgs__glyph--call {
  color: var(--warn);
  -webkit-mask-image: var(--glyph-call);
  mask-image: var(--glyph-call);
}
.sgs__glyph--file {
  color: var(--fg-muted);
  -webkit-mask-image: var(--glyph-file);
  mask-image: var(--glyph-file);
}

/* ---- Motion ---- */

.sgs__row--in { opacity: 0; }
/* Staggered to follow the pile emptying, so the two read as one movement. */
.sgs__row--a1 { --delay: 0.35s; --ax: -14%; --ay: 30px;  --arc: -18px; }
.sgs__row--a2 { --delay: 0.65s; --ax: -20%; --ay: -34px; --arc:  22px; }
.sgs__row--a3 { --delay: 0.95s; --ax: -16%; --ay: 26px;  --arc: -14px; }
.sgs__row--a4 { --delay: 1.25s; --ax: -22%; --ay: -22px; --arc:  20px; }
.sgs__row--a5 { --delay: 1.55s; --ax: -18%; --ay: 34px;  --arc: -16px; }

.sgs__row--in .sgs__dot { opacity: 0; }

/* Declared here, not on the base rule with a paused play state: a finished
   animation stays finished when paused, so play-state alone cannot rewind
   it. Attaching the animation to the attribute means removing the attribute
   returns every element to its base state and re-adding it plays again. */
.sg[data-s1] .sgs__card {
  animation: sgs-depart 0.75s cubic-bezier(.42, 0, .25, 1) var(--delay) both;
}
.sg[data-s1] .sgs__row--in {
  animation: sgs-arrive 0.9s cubic-bezier(.42, 0, .25, 1) var(--delay) both;
}
.sg[data-s1] .sgs__row--in .sgs__dot {
  animation: sgs-dot 0.35s ease calc(var(--delay) + 0.75s) both;
}

@keyframes sgs-depart {
  0%   { opacity: 1; transform: translate(0, 0) rotate(var(--rot)) scale(1); }
  100% { opacity: 0; transform: translate(38%, -8px) rotate(0deg) scale(0.92); }
}
@keyframes sgs-arrive {
  0%   { opacity: 0; transform: translate(var(--ax), var(--ay)) scale(1.06); }
  45%  { opacity: 1; transform: translate(calc(var(--ax) / 2), var(--arc)) scale(1.03); }
  100% { opacity: 1; transform: translate(0, 0) scale(1); }
}
@keyframes sgs-dot {
  0%   { opacity: 0; }
  100% { opacity: 1; }
}

/* The settle. The last row lands at 2.45s; the empty half then closes and
   the threads take the full width, which is the frame that rests on screen.
   The handoff did this by sliding a fixed-width column; the equivalent for
   a reflowing grid is to collapse the track. */
.sg[data-s1] .sgs__in { animation: sgs-clear 0.5s ease 2.55s both; }

/* Transform only: no track re-solves, no reflow, no size change. */
@container (min-width: 660px) {
  .sg[data-s1] .sgs { animation: sgs-settle 0.9s cubic-bezier(.5, 0, .2, 1) 2.55s both; }
}

@keyframes sgs-clear {
  0%   { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}
@keyframes sgs-settle {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-22%); }
}

/* End state without motion, for no-JS and reduced motion: the pile has
   already gone and the threads already hold the full width. */
.no-js .sg--stream .sgs,
.no-js .sg--stream .sgs__in,
.no-js .sg--stream .sgs__card,
.no-js .sg--stream .sgs__row--in,
.no-js .sg--stream .sgs__row--in .sgs__dot { animation: none; }
.no-js .sg--stream .sgs { grid-template-columns: 1fr; gap: 0; transform: none; }
.no-js .sg--stream .sgs__in { display: none; }
.no-js .sg--stream .sgs__row--in { opacity: 1; transform: none; }
.no-js .sg--stream .sgs__row--in .sgs__dot { opacity: 1; }

/* --------------------------------------------------------------------------
   02 — work monitor across all projects
   -------------------------------------------------------------------------- */

.sg--monitor { display: flex; flex-direction: column; gap: 16px; }

.sg-mon__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line-2);
}
.sg-mon__tally {
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
  color: rgba(250, 250, 250, 0.66);
}
.sg-count {
  display: inline-block;
  font-weight: 600;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}
/* Stops the trailing text shifting as the count crosses to two digits. */
.sg-count--wide { min-width: 2ch; text-align: right; }

.sg-mon__list { display: flex; flex-direction: column; gap: 8px; }

.sg-mon__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 14px;
  padding: 13px 16px;
  border-radius: 8px;
  border: 1px solid rgba(250, 250, 250, 0.12);
  background: rgba(250, 250, 250, 0.035);
  opacity: 0;
  transform: translateY(6px);
  /* Paced to match step 01, whose last row lands at ~2.4s. At the original
     .45s and 90ms the whole list was over in a second, before a reader
     scrolling at normal speed had it in view. */
  transition: opacity .7s cubic-bezier(.2, .8, .3, 1),
              transform .7s cubic-bezier(.2, .8, .3, 1);
  transition-delay: calc(var(--i) * 180ms);
}
.sg-mon__row--closed {
  border-color: rgba(250, 250, 250, 0.08);
  background: rgba(250, 250, 250, 0.02);
}
.sg-mon__list > :nth-child(1) { --i: 0; }
.sg-mon__list > :nth-child(2) { --i: 1; }
.sg-mon__list > :nth-child(3) { --i: 2; }
.sg-mon__list > :nth-child(4) { --i: 3; }
.sg-mon__list > :nth-child(5) { --i: 4; }
.sg-mon__list > :nth-child(6) { --i: 5; }

.sg-mon__main { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.sg-mon__line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.sg-mon__title {
  margin: 0;
  font-size: 15px;
  line-height: 1.3;
  font-weight: 600;
  color: var(--fg);
}
.sg-mon__proj {
  font: 400 10px/1.3 var(--font-mono);
  letter-spacing: 0.08em;
  color: rgba(250, 250, 250, 0.50);
}
.sg-mon__why {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--fg-muted);
}
.sg-mon__row--closed .sg-mon__title { color: rgba(250, 250, 250, 0.80); }
.sg-mon__row--closed .sg-mon__why { color: rgba(250, 250, 250, 0.62); }

/* Idle tone lives in the base rule, so reduced-motion and no-JS users never
   see it. Do not move the real tones up here. */
.sg-pill {
  flex: 0 0 auto;
  padding: 5px 11px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  color: rgba(250, 250, 250, 0.38);
  background: rgba(250, 250, 250, 0.05);
  border: 1px solid rgba(250, 250, 250, 0.12);
  transition: color .7s ease, background-color .7s ease, border-color .7s ease;
  /* --i inherits from the row, so no extra markup for the stagger. */
  transition-delay: calc(var(--i) * 140ms);
}

.sg-mon__foot {
  margin: 0;
  font: 400 11px/1.4 var(--font-mono);
  letter-spacing: 0.06em;
  color: rgba(250, 250, 250, 0.50);
}

:is(.sg[data-s1], .no-js .sg) .sg-mon__row { opacity: 1; transform: translateY(0); }

:is(.sg[data-s2], .no-js .sg) .sg-pill[data-tone="late"] {
  color: var(--late); background: var(--late-bg); border-color: var(--late-line);
}
:is(.sg[data-s2], .no-js .sg) .sg-pill[data-tone="due"] {
  color: var(--warn); background: var(--warn-bg); border-color: var(--warn-line);
}
:is(.sg[data-s2], .no-js .sg) .sg-pill[data-tone="waiting"] {
  color: rgba(250, 250, 250, 0.72);
  background: rgba(250, 250, 250, 0.06);
  border-color: rgba(250, 250, 250, 0.18);
}
:is(.sg[data-s2], .no-js .sg) .sg-pill[data-tone="clear"] {
  color: var(--accent);
  background: rgba(149, 224, 102, 0.10);
  border-color: rgba(149, 224, 102, 0.30);
}

/* --------------------------------------------------------------------------
   03 — question, sources, answer

   The connector SVG is hard geometry: six 56px rows with 10px gaps give
   6*56 + 5*10 = 386px, and the three cited rows sit at y = 28, 160, 292.
   Row height, row gap and the .sg__label line box above the list must not
   change without redrawing the paths in index.html.
   -------------------------------------------------------------------------- */

/* Panel first, in the DOM as well as on screen: stacked, that gives the
   question above the events with no `order`, which would leave the reading
   order and the visual order disagreeing. */
.sg-ask__grid {
  display: grid;
  grid-template-columns: 1.05fr 72px 1fr;
  gap: 0;
  align-items: start;
}
.sg-ask__panel,
.sg-ask__events { display: flex; flex-direction: column; gap: 12px; min-width: 0; }

/* The lightest surface in the section: the panel is what the reader is meant
   to look at, and the event cards below step down from it. Same white as
   everything else at a different alpha, so no new hue enters the palette. */
.sg-ask__panel {
  padding: 18px;
  border-radius: 10px;
  border: 1px solid rgba(250, 250, 250, 0.13);
  background: rgba(250, 250, 250, 0.05);
}

.sg-ev {
  height: 56px;
  box-sizing: border-box;
  padding: 0 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-radius: 8px;
  border: 1px solid rgba(250, 250, 250, 0.08);
  background: rgba(250, 250, 250, 0.02);
  overflow: hidden;
  transition: border-color .25s ease, background-color .25s ease,
              box-shadow .25s ease, opacity .3s ease;
}
.sg-ev__body { min-width: 0; }
.sg-ev__meta,
.sg-ev__title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sg-ev__meta {
  margin: 0 0 2px;
  font: 400 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.07em;
  color: rgba(250, 250, 250, 0.66);
}
.sg-ev__title {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.3;
  color: rgba(250, 250, 250, 0.88);
}

.sg-ev__badge {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 500 10.5px/1 var(--font-mono);
  opacity: 0;
  transform: scale(0.6);
  transition: opacity .35s ease, transform .35s ease;
}

/* min-width: 0 all the way down, or the nowrap row titles set a min-content
   width that the column cannot shrink below and the badges push out of the
   card on narrow screens. */
.sg-ev-list { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.sg-ev { min-width: 0; }

/* The connector column is offset by the label's 16px line box plus the 12px
   column gap, so the paths meet the rows they point at. */
.sg-conn {
  width: 72px;
  height: 386px;
  margin-top: 28px;
  overflow: visible;
}
.sg-conn__path {
  stroke: var(--accent);
  stroke-width: 1.25;
  fill: none;
  /* pathLength="1" normalises three different arc lengths to one draw time. */
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0;
  transition: stroke-dashoffset .9s cubic-bezier(.4, 0, .2, 1),
              opacity .9s linear,
              stroke-width .2s ease;
  transition-delay: calc(100ms + var(--i) * 180ms);
}
.sg-conn__path[data-src="1"] { --i: 0; }
.sg-conn__path[data-src="2"] { --i: 1; }
.sg-conn__path[data-src="3"] { --i: 2; }
.sg-conn__dot {
  fill: var(--accent);
  opacity: 0;
  transition: opacity .4s ease;
}

.sg-ask__head { display: flex; align-items: center; gap: 9px; }
.sg-ask__mark {
  width: 7px;
  height: 7px;
  background: var(--accent);
  transform: rotate(45deg);
  flex: 0 0 auto;
}

.sg-q {
  margin: 0;
  border: 1px solid rgba(250, 250, 250, 0.14);
  border-radius: 8px;
  background: rgba(250, 250, 250, 0.05);
  padding: 14px 16px;
  font-size: 15px;
  line-height: 1.45;
  color: var(--fg);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .6s ease, transform .6s ease;
}

.sg-a {
  border-top: 1px solid var(--line-2);
  padding-top: 18px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .7s ease, transform .7s ease;
}
.sg-a__lead {
  margin: 0 0 12px;
  font-size: 15px;
  line-height: 1.5;
  font-weight: 600;
  color: var(--fg);
}
.sg-a__text {
  margin: 0;
  font-size: 15px;
  line-height: 1.72;
  color: rgba(250, 250, 250, 0.82);
}
.sg-a__date { font-weight: 600; color: var(--fg); }
.sg-a__count {
  margin: 14px 0 0;
  font: 400 11.5px/1.3 var(--font-mono);
  letter-spacing: 0.05em;
  color: var(--accent);
}

.sg-cite {
  position: relative;
  display: inline-block;
  margin-left: 3px;
  padding: 1px 5px;
  border-radius: 4px;
  font: 400 10px/1.4 var(--font-mono);
  vertical-align: super;
  cursor: pointer;
  color: var(--accent);
  background: rgba(149, 224, 102, 0.14);
  border: 1px solid rgba(149, 224, 102, 0.30);
  opacity: 0;
  transition: opacity .4s ease, color .2s ease,
              background-color .2s ease, border-color .2s ease;
  transition-delay: calc(var(--i) * 120ms);
}
.sg-cite[data-src="1"] { --i: 0; }
.sg-cite[data-src="2"] { --i: 1; }
.sg-cite[data-src="3"] { --i: 2; }
/* The chip is ~20x16px. Reach the 24x24 minimum without visible padding. */
.sg-cite::after { content: ''; position: absolute; inset: -6px; }

/* Stage 1: the question. Stage 2: cited rows light, badges pop, connectors
   draw, un-cited rows recede. Stage 3: the answer and its citations. */
:is(.sg[data-s1], .no-js .sg) .sg-q { opacity: 1; transform: translateY(0); }

:is(.sg[data-s2], .no-js .sg) .sg-ev:not(.sg-ev--cited) { opacity: .72; }
:is(.sg[data-s2], .no-js .sg) .sg-ev--cited {
  border-color: rgba(149, 224, 102, 0.55);
  background: rgba(149, 224, 102, 0.08);
  box-shadow: 0 0 0 3px rgba(149, 224, 102, 0.06);
}
:is(.sg[data-s2], .no-js .sg) .sg-ev__badge { opacity: 1; transform: scale(1); }
:is(.sg[data-s2], .no-js .sg) .sg-conn__path { stroke-dashoffset: 0; opacity: .55; }
:is(.sg[data-s2], .no-js .sg) .sg-conn__dot { opacity: 1; transition-delay: 800ms; }

:is(.sg[data-s3], .no-js .sg) .sg-a { opacity: 1; transform: translateY(0); }
:is(.sg[data-s3], .no-js .sg) .sg-cite { opacity: 1; }

/* Citation highlight. data-hot on the root rather than a class pair on nine
   elements, so which elements react is expressed here and not in JS. */
.sg--ask[data-hot] .sg-ev:not(.sg-ev--cited) { opacity: .5; }

.sg--ask[data-hot="1"] .sg-ev[data-src="1"],
.sg--ask[data-hot="2"] .sg-ev[data-src="2"],
.sg--ask[data-hot="3"] .sg-ev[data-src="3"] {
  border-color: rgba(149, 224, 102, 0.95);
  background: rgba(149, 224, 102, 0.16);
  box-shadow: 0 0 0 4px rgba(149, 224, 102, 0.14);
  opacity: 1;
}
.sg--ask[data-hot="1"] .sg-cite[data-src="1"],
.sg--ask[data-hot="2"] .sg-cite[data-src="2"],
.sg--ask[data-hot="3"] .sg-cite[data-src="3"] {
  color: var(--bg);
  background: var(--accent);
  border-color: var(--accent);
}
.sg--ask[data-hot="1"] .sg-conn__path[data-src="1"],
.sg--ask[data-hot="2"] .sg-conn__path[data-src="2"],
.sg--ask[data-hot="3"] .sg-conn__path[data-src="3"] {
  opacity: 1;
  stroke-width: 2;
}
.sg--ask[data-hot="1"] .sg-conn__path:not([data-src="1"]),
.sg--ask[data-hot="2"] .sg-conn__path:not([data-src="2"]),
.sg--ask[data-hot="3"] .sg-conn__path:not([data-src="3"]) { opacity: .28; }

/* Below 720px the columns stack and the connector has nothing to connect. */
@container (max-width: 720px) {
  /* align-items: start carries over from the grid layout, where it is
     correct. In a column flex box it stops the children stretching to the
     container width, so the nowrap rows overflow the card. */
  .sg-ask__grid { display: flex; flex-direction: column; gap: 28px; align-items: stretch; }
  .sg-conn { display: none; }
}

/* --------------------------------------------------------------------------
   The problem — one wall, followed through time

   Three moments on one rail: the decision scattering, the question nobody
   tracks, and the reasoning walking out of the door.

   A column's state is carried by an inherited --on rather than by a
   selector per element. The properties that animate read it directly
   (opacity: var(--on)), so flipping one custom property on the column
   drives the whole column and the stage selectors stay flat. Setting it
   also gives the reduced-motion and no-JS end states for free, since the
   stages are cumulative.
   -------------------------------------------------------------------------- */

/* No card: this one sits on the page, not in a panel like the step graphics. */
.sg--wall {
  border: 0;
  background: none;
  padding: 0;
  margin-top: clamp(34px, 5vw, 56px);
}

/* The question the three columns spend the next hour failing to answer.
   Above the rail and in the first column's green, so the heading hands the
   reader into the story instead of dropping them at the first card. A step
   larger than the column labels, because it is the thing being asked. */
.sg-w__ask {
  margin: 0 0 clamp(18px, 2.4vw, 28px);
  font: 500 13px/1.4 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

/* The gaps are real grid columns, not a `gap`, so the interval markers have
   somewhere to live and the dashed run between nodes can span them. */
.sg-w {
  --w-gap: clamp(30px, 7vw, 92px);
  display: grid;
  grid-template-columns: 1fr var(--w-gap) 1fr var(--w-gap) 1fr;
  grid-template-rows: auto auto 1fr auto;
}

/* display: contents so the four parts of each column are placed into rows
   shared by all three. A column that is its own flex box can only align its
   caption to the bottom, which puts a three-line caption higher than a
   two-line one; the captions have to start on one line, not end on one.
   Placement is explicit because auto-placement fills across, not down.
   Inheritance is unaffected, so --on and --tone still reach the children. */
.sg-w__col {
  --on: 0;
  --tone: var(--accent);
  display: contents;
}
.sg-w__col:nth-child(1) > * { grid-column: 1; }
.sg-w__col:nth-child(3) > * { grid-column: 3; }
.sg-w__col:nth-child(5) > * { grid-column: 5; }
.sg-w__rail { grid-row: 1; }
.sg-w__when { grid-row: 2; }
.sg-w__main { grid-row: 3; }
.sg-w__note { grid-row: 4; }
.sg-w__col--late { --tone: var(--late); }
.sg-w__col--cold { --tone: rgba(250, 250, 250, 0.55); }

.sg-w__gap { --bridged: 0; position: relative; grid-row: 1 / -1; }

/* Column n lights at stage n; the gap after it once the next column lands. */
.sg[data-s1] .sg-w__col:nth-child(1),
.sg[data-s2] .sg-w__col:nth-child(3),
.sg[data-s3] .sg-w__col:nth-child(5),
.no-js .sg-w__col { --on: 1; }

.sg[data-s2] .sg-w__gap:nth-child(2),
.sg[data-s3] .sg-w__gap:nth-child(4),
.no-js .sg-w__gap { --bridged: 1; }

/* ---- Rail ---- */

.sg-w__rail { position: relative; height: 9px; margin-bottom: 15px; }

.sg-w__node {
  position: absolute;
  left: 0;
  top: 0;
  width: 9px;
  height: 9px;
  background: var(--tone);
  opacity: var(--on);
  transform: scale(calc(0.3 + 0.7 * var(--on)));
  transition: opacity .3s ease, transform .4s cubic-bezier(.2, .8, .3, 1);
}
/* Nothing was ever recorded, so the last node is an empty outline. */
.sg-w__node--open { background: none; border: 1px solid var(--tone); }

.sg-w__line {
  position: absolute;
  left: 15px;
  right: 0;
  top: 4px;
  height: 1px;
  background: var(--tone);
  opacity: calc(var(--on) * 0.45);
  transform: scaleX(var(--on));
  transform-origin: left center;
  transition: transform .7s cubic-bezier(.4, 0, .2, 1) .1s, opacity .4s ease .1s;
}

.sg-w__dash {
  position: absolute;
  left: 0;
  right: 0;
  top: 4px;
  height: 1px;
  background: repeating-linear-gradient(to right,
    var(--line-n) 0 4px, transparent 4px 9px);
  opacity: var(--bridged);
  transform: scaleX(var(--bridged));
  transform-origin: left center;
  transition: transform .55s cubic-bezier(.4, 0, .2, 1), opacity .4s ease;
}
/* A sibling of the dash, not a child: inside it the scaleX would squash the
   text as the run draws. */
.sg-w__span {
  position: absolute;
  left: 0;
  right: 0;
  top: 15px;
  text-align: center;
  font: 400 9.5px/1.3 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-faint);
  white-space: nowrap;
  opacity: var(--bridged);
  transition: opacity .5s ease .15s;
}
/* Holds the three stacks apart where the rail above them cannot. */
.sg-w__gap::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 34%;
  height: 22%;
  border-left: 1px dashed var(--line-n);
  opacity: calc(var(--bridged) * 0.8);
  transition: opacity .5s ease .2s;
}

/* ---- Column head, body, caption ---- */

.sg-w__when {
  margin: 0 0 18px;
  font: 500 10.5px/1.45 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tone);
  opacity: var(--on);
  transform: translateY(calc((1 - var(--on)) * 5px));
  transition: opacity .5s ease .15s, transform .5s ease .15s;
}

/* Row 3 is the 1fr, so this absorbs the slack and the padding guarantees a
   gap above the caption in whichever column is tallest. */
.sg-w__main { min-width: 0; padding-bottom: 30px; }

.sg-w__body { display: flex; flex-direction: column; align-items: stretch; gap: 12px; }

.sg-w__card {
  /* Resting offset and angle, plus the extra --dx/--dy/--rot0 each card
     arrives from. Both fade out as --on goes to 1, so one property drives
     position, rotation and the settle. */
  --dx: 0px;
  --dy: 14px;
  --rot: 0deg;
  --rot0: 0deg;
  border: 1px dashed var(--line-n);
  border-radius: 8px;
  /* Opaque, not a white wash: the scattered cards overlap and a translucent
     fill would show the one beneath showing through the join. The page
     colour lifted a touch, so it still reads as a card. */
  background: #0C2210;
  background: color-mix(in srgb, var(--bg) 96%, #FAFAFA);
  padding: 11px 13px;
  opacity: var(--on);
  transform:
    translate(calc((1 - var(--on)) * var(--dx)), calc((1 - var(--on)) * var(--dy)))
    rotate(calc(var(--rot) + (1 - var(--on)) * var(--rot0)));
  transition: opacity .55s ease, transform .6s cubic-bezier(.2, .8, .3, 1);
  transition-delay: 0.28s;
}

/* Dropped, not filed. Each one sits at its own angle and indent, comes in
   from a different direction at a different moment, and lands out of order,
   so the eye reads three separate places rather than a list of three. The
   angles stay under two degrees: past that the text starts to look like a
   mistake instead of a mess. */
.sg-w__card--item { display: flex; align-items: center; gap: 10px; }
.sg-w__card--i1 {
  --rot: -2.1deg; --rot0: 2.6deg; --dx: -16px; --dy: -10px;
  margin-right: 10%;
  transition-delay: .34s;
}
.sg-w__card--i2 {
  --rot: 1.9deg; --rot0: -3deg; --dx: 20px; --dy: 8px;
  margin: -20px 1% 0 17%;
  transition-delay: .22s;
}
.sg-w__card--i3 {
  --rot: -1.4deg; --rot0: 3.4deg; --dx: -12px; --dy: 18px;
  margin: -14px 9% 0 5%;
  transition-delay: .56s;
}

.sg-w__t {
  margin: 0;
  min-width: 0;
  font-size: 13.5px;
  line-height: 1.3;
  color: rgba(250, 250, 250, 0.90);
}
.sg-w__kind {
  margin-left: auto;
  flex: 0 0 auto;
  font: 400 8.5px/1 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.30);
}

/* Same mask tokens and the same colour per kind as step 01. */
.sg-w__glyph {
  flex: 0 0 auto;
  width: 13px;
  height: 13px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}
.sg-w__glyph--email {
  color: var(--accent);
  -webkit-mask-image: var(--glyph-email);
  mask-image: var(--glyph-email);
}
.sg-w__glyph--call {
  color: var(--warn);
  -webkit-mask-image: var(--glyph-call);
  mask-image: var(--glyph-call);
}
.sg-w__glyph--file {
  color: var(--fg-muted);
  -webkit-mask-image: var(--glyph-file);
  mask-image: var(--glyph-file);
}
.sg-w__glyph--comment {
  color: var(--fg-muted);
  -webkit-mask-image: var(--glyph-comment);
  mask-image: var(--glyph-comment);
}

.sg-w__card--open {
  border-style: solid;
  border-color: var(--late-line);
  background: var(--late-bg);
  padding: 15px 16px;
}
.sg-w__card--gone { padding: 15px 16px; }

.sg-w__q {
  margin: 0 0 9px;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--fg);
}
.sg-w__p { margin: 0; font-size: 13px; line-height: 1.5; color: var(--fg-muted); }
.sg-w__mark {
  margin: 18px 0 14px;
  font: 600 40px/1 var(--font-display);
  color: rgba(250, 250, 250, 0.20);
}
.sg-w__none {
  margin: 0;
  font: 400 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.07em;
  color: rgba(250, 250, 250, 0.36);
}

.sg-w__flag {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--late-line);
  background: var(--late-bg);
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--late);
  opacity: var(--on);
  transition: opacity .5s ease .6s;
}
.sg-w__flag::before {
  content: '';
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--late);
}

.sg-w__after {
  margin: 14px 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--fg-muted);
  opacity: var(--on);
  transition: opacity .55s ease .5s;
}

.sg-w__note {
  margin: 0;
  padding-top: 16px;
  border-top: 1px solid var(--line-2);
  font-size: 14px;
  line-height: 1.55;
  color: var(--fg-muted);
  opacity: var(--on);
  transition: opacity .6s ease .55s;
}

/* Two more dropped cards, on the same rules as the first three: its own
   angle, its own indent, its own arrival moment, landing out of order. */
.sg-w__card--i4 {
  --rot: 2.4deg; --rot0: -2.2deg; --dx: 15px; --dy: -13px;
  margin: -16px 4% 0 13%;
  transition-delay: .45s;
}
.sg-w__card--i5 {
  --rot: -1.7deg; --rot0: 2.9deg; --dx: -18px; --dy: 12px;
  margin: -18px 12% 0 2%;
  transition-delay: .66s;
}

/* A jotted note: the file mask again, dimmed, so it reads as its own kind
   without a fourth glyph token to keep in step with the other three. */
.sg-w__glyph--note {
  color: var(--fg-soft);
  -webkit-mask-image: var(--glyph-file);
  mask-image: var(--glyph-file);
}

/* ---- The search that gets close ---- */

.sg-w__card--search {
  display: flex;
  align-items: center;
  gap: 10px;
  border-style: solid;
  border-color: var(--line-3);
  border-radius: 999px;
  padding: 13px 17px;
}
/* A real magnifier on the same mask mechanism as the other glyphs, rather
   than a circle with a rotated bar stuck to it: at this size the drawn
   version reads as a smudge. Takes the column's tone like everything here. */
.sg-w__find {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  background-color: var(--tone);
  -webkit-mask-image: var(--glyph-search);
  mask-image: var(--glyph-search);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}
.sg-w__query {
  margin: 0;
  min-width: 0;
  font: 400 13.5px/1.3 var(--font-mono);
  color: var(--fg);
}

/* What the search does return. The count and the tail matter as much as the
   rows: fifty hits and not one of them the answer. */
.sg-w__count {
  margin: 2px 0 0;
  font: 400 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-faint);
  opacity: var(--on);
  transition: opacity .5s ease .35s;
}
.sg-w__results {
  display: flex;
  flex-direction: column;
  gap: 4px;
  opacity: var(--on);
  transition: opacity .55s ease .4s;
}
/* A result list, not a stack of cards: one hairline between rows. The
   subject truncates rather than wraps, so every row is the same height and
   the reasons line up down the right edge, which is the point. */
.sg-w__hit {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--line-2);
}
.sg-w__hit .sg-w__t {
  flex: 1;
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Why this one is not the answer. Muted rather than loud: the point is the
   pile, not any single miss. */
.sg-w__miss {
  flex: 0 0 auto;
  white-space: nowrap;
  font: 400 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--late);
  opacity: 0.72;
}
/* Dimmer than the count above it: the tail is the size of the pile, not
   something to read. */
.sg-w__more {
  margin: 0;
  padding: 8px 0 0 2px;
  font: 400 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.34);
}

/* Three columns at tablet width leave each result about 250px, and the
   reason cannot shrink, so the subject truncates to nothing. Only in that
   band, the reason takes its own line and the subject gets the row back.
   Wider than this the design's single line holds; narrower, the columns
   stack and the width returns anyway. */
@media (min-width: 820px) and (max-width: 1100px) {
  .sg-w__hit { flex-wrap: wrap; }
  .sg-w__hit .sg-w__t {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
  .sg-w__miss { flex: 0 0 100%; text-align: right; }
}

/* ---- Found, two levels down ---- */

/* Green, like every other border in this graphic. The neutral hairline the
   scattered cards use is for paper dropped on a desk; this is a record. */
.sg-w__card--nest {
  border-style: solid;
  border-color: var(--line-3);
  border-radius: 10px;
  padding: 13px 13px;
}
/* Each level is a box inside the one above: the depth is the whole point. */
/* No left indent: the box inside the box is what carries the depth, and an
   indent as well just eats the width the filename needs. */
.sg-w__nest {
  margin: 13px 0 0;
  padding: 11px 12px;
  /* A shade lighter than the box holding it, so the nesting reads as depth
     rather than as two unrelated boxes. No fill: the card behind it already
     separates the levels, and a wash only greys the green out. */
  border: 1px solid var(--line-4);
  border-radius: 8px;
}
.sg-w__line-item {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 0;
  min-width: 0;
}
/* Glyph and label sit against the first line of a title that may wrap. */
.sg-w__line-item .sg-w__glyph { margin-top: 1px; }
.sg-w__line-item .sg-w__kind { margin-top: 3px; }
/* Kind first here rather than pushed right: these read top down, not as a
   row of cards. Brighter and green-tinted too, because here the label is
   doing work, naming the level rather than trailing a card. */
.sg-w__kind--lead {
  margin-left: 0;
  color: rgba(190, 214, 193, 0.58);
}

/* Above the card, not under it, and in coral: the folder is the whole
   problem, so it leads rather than trails. No text-transform, or the path
   itself would come out shouting and wrong. */
.sg-w__path {
  margin: 0 0 13px;
  font: 500 11.5px/1.4 var(--font-mono);
  letter-spacing: 0.06em;
  color: var(--late);
  opacity: var(--on);
  transition: opacity .55s ease .5s;
}

/* Stacked, the rail cannot run left to right, so each interval becomes a
   vertical tick with its label beside it and time still reads as passing. */
@media (max-width: 819px) {
  .sg-w { grid-template-columns: 1fr; grid-template-rows: none; }
  /* Back to a box per column: with one column, rows shared across three
     columns would put all three rails in row 1 on top of each other. */
  .sg-w__col { display: flex; flex-direction: column; min-width: 0; }
  .sg-w__gap { grid-row: auto; }
  .sg-w__gap { height: 62px; }
  .sg-w__gap::after { display: none; }
  .sg-w__dash {
    left: 4px;
    right: auto;
    top: 10px;
    bottom: 10px;
    width: 1px;
    height: auto;
    background: repeating-linear-gradient(to bottom,
      var(--line-n) 0 4px, transparent 4px 9px);
    transform: scaleY(var(--bridged));
    transform-origin: top center;
  }
  .sg-w__span {
    left: 20px;
    right: auto;
    top: 50%;
    transform: translateY(-50%);
    text-align: left;
  }
  .sg-w__main { padding-bottom: 22px; }
  /* Narrower column, so the indents come in; the angles and the pile stay. */
  .sg-w__card--i1 { margin-right: 6%; }
  /* Arrives from the left here, not the right: this card rests against the
     column's right edge, and on a phone that edge is the screen edge. */
  .sg-w__card--i2 { --dx: -18px; margin: -16px 0 0 11%; }
  .sg-w__card--i3 { margin: -10px 5% 0 3%; }
  .sg-w__card--i4 { --dx: -14px; margin: -14px 2% 0 9%; }
  .sg-w__card--i5 { margin: -12px 8% 0 1%; }
}
