/* ==========================================================================
   Cloud9 Ops — "The Quiet Ledger"
   --------------------------------------------------------------------------
   The product being sold is the absence of events, so the design is built
   around an operations artifact rather than decoration: a 90-day incident
   ledger where almost nothing happened.

   Deliberately light. Every competitor in this category — and the previous
   version of this site — is near-black with one bright accent. Going to paper
   is the one real risk here, and it is what makes the page not look like a
   vendor promising transformation.

   Colour carries meaning and nothing else: the ledger's quiet days are plain
   graphite, and rust appears exactly once on the page, on the one incident
   that actually happened.
   ========================================================================== */

:root {
  /* Cool bone, not warm cream. Warm cream + serif + terracotta is the most
     recognisable machine-generated palette going; this leans green-grey and
     reads like newsprint or an instrument face instead. */
  --paper:        #F1F2EE;
  --paper-raised: #FBFBF9;
  --paper-sunk:   #E7E9E3;

  --graphite:     #171A19;
  --graphite-soft:#3A3F3C;
  --muted:        #6A6F6A;
  --faint:        #979C96;

  --rule:         #D6D8D2;
  --rule-strong:  #BFC2BA;

  /* Interactive. Verdigris — oxidised copper, an instrument patina, and
     pointedly not the category's cyan-on-navy. */
  --verdigris:      #2F6B5C;
  --verdigris-deep: #224F45;
  --verdigris-wash: #E4EDE9;

  /* The mark. Used once. */
  --rust:      #B4472E;
  --rust-wash: #F6E7E2;

  /* Archivo: a grotesque with actual width and weight range, so headings can
     be set tight and structural. Public Sans for text — the typeface of
     public infrastructure that simply has to work, which is the whole pitch.
     Mono is reserved for real data: dates, durations, counts. Never for mood. */
  --display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --body:    'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono:    'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --max-w: 1080px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);

  /* Barely-there radius. Zero radius everywhere is its own cliché; this is
     enough to feel drawn rather than stamped. */
  --r: 3px;

  --s1: 0.5rem;
  --s2: 0.875rem;
  --s3: 1.5rem;
  --s4: 2.5rem;
  --s5: 4rem;
  --s6: 6.5rem;
}

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

html {
  -webkit-text-size-adjust: 100%;
  /* Tells the browser this is a light UI so scrollbars, form controls and other
     device chrome get the right contrast rather than guessing. */
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--graphite);
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

a { color: var(--verdigris); text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* First focusable element on the page. Off-screen until focused, so keyboard
   users can jump the nav without it appearing for anyone else. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--graphite);
  color: var(--paper);
  padding: 0.75rem 1.1rem;
  border-radius: 0 0 var(--r) 0;
  text-decoration: none;
  font-size: 0.9375rem;
}

.skip-link:focus { left: 0; }

#main:focus { outline: none; }
a:hover { color: var(--graphite); }

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

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

/* ---------------------------------------------------------------- type */

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.022em;
  margin: 0 0 var(--s3);
  text-wrap: balance;
}

h1 { font-size: clamp(2.6rem, 6.4vw, 4.5rem); }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.75rem); }
h3 { font-size: 1.1875rem; letter-spacing: -0.012em; margin-bottom: var(--s1); }

p { margin: 0 0 var(--s3); max-width: 62ch; }
p:last-child { margin-bottom: 0; }

/* Eyebrow. Set in mono because it is a label on an instrument, not styling. */
.kicker {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--s2);
  display: block;
}

.lede {
  font-size: clamp(1.0625rem, 1.9vw, 1.25rem);
  color: var(--graphite-soft);
  max-width: 56ch;
}

.section-head { margin-bottom: var(--s5); max-width: 64ch; }

/* ---------------------------------------------------------------- header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--rule);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  min-height: 68px;
}

.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: 0.09em;
  color: var(--graphite);
  text-decoration: none;
  white-space: nowrap;
}

/* Height-constrained, width auto: the mark is 3:2, so pinning both axes to the
   same value distorts it and renders it far smaller than the space allows. */
.nav-brand img {
  height: 30px;
  width: auto;
  border-radius: 2px;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--s3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a {
  font-size: 0.9375rem;
  color: var(--muted);
  text-decoration: none;
  /* 24px minimum hit target: 15px line-box plus 5px each side. */
  padding-block: 0.35rem;
  min-height: 24px;
  display: inline-flex;
  align-items: center;
  border-bottom: 1.5px solid transparent;
}

.nav-links a:hover { color: var(--graphite); }
.nav-links a.active { color: var(--graphite); border-bottom-color: var(--graphite); }

.nav-toggle {
  touch-action: manipulation;
  display: none;
  background: none;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r);
  color: var(--graphite);
  font-size: 1rem;
  line-height: 1;
  padding: 0.5rem 0.65rem;
  cursor: pointer;
}

/* Status pill. Quiet by default — it is only interesting when it is not. */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
  white-space: nowrap;
}

.status-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--verdigris);
  flex: none;
}

/* ---------------------------------------------------------------- buttons */

.btn {
  /* Prevents the double-tap-to-zoom gesture, which otherwise delays the tap. */
  touch-action: manipulation;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-family: var(--body);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1;
  padding: 0.85rem 1.35rem;
  border-radius: var(--r);
  border: 1px solid var(--rule-strong);
  background: transparent;
  color: var(--graphite);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.btn:hover { border-color: var(--graphite); color: var(--graphite); background: var(--paper-raised); }

.btn-primary {
  background: var(--graphite);
  border-color: var(--graphite);
  color: var(--paper);
}

.btn-primary:hover { background: var(--verdigris); border-color: var(--verdigris); color: #fff; }

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

section { padding-block: var(--s6); }

.section-alt {
  background: var(--paper-sunk);
  border-block: 1px solid var(--rule);
}

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

.hero {
  padding-top: clamp(3.5rem, 9vw, 6.5rem);
  padding-bottom: var(--s6);
}

.hero h1 { max-width: 15ch; margin-bottom: var(--s3); }

.hero .lede { margin-bottom: var(--s4); }

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-bottom: var(--s6);
}

/* ------------------------------------------------------- the ledger (signature) */

.ledger {
  border-top: 1px solid var(--graphite);
  padding-top: var(--s2);
}

.ledger-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s3);
}

.ledger-title {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--graphite);
}

.ledger-meta {
  font-variant-numeric: tabular-nums;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.ledger-chart { width: 100%; height: auto; display: block; overflow: visible; }

/* Quiet days are plain marks — the absence is not colour-coded, because
   nothing happening is the normal state, not a success condition. */
.tick { fill: var(--rule-strong); }
.tick-incident { fill: var(--rust); }

.ledger-axis { fill: var(--faint); font-family: var(--mono); font-size: 9px; letter-spacing: 0.06em; }
.ledger-callout { fill: var(--graphite); font-family: var(--mono); font-size: 10px; }
.ledger-leader { stroke: var(--rule-strong); stroke-width: 1; }

.ledger-foot {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-top: var(--s3);
  padding-top: var(--s2);
  border-top: 1px solid var(--rule);
}

.ledger-claim {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.05rem, 2.1vw, 1.4rem);
  letter-spacing: -0.015em;
  margin: 0;
  max-width: none;
}

.ledger-note { font-variant-numeric: tabular-nums; font-family: var(--mono); font-size: 0.6875rem; color: var(--muted); margin: 0; max-width: none; }

/* ---------------------------------------------------------------- runbook (home) */

/* A runbook index, not a grid of icon cards. Rules separate rows; the label
   sits in a fixed gutter so the column edge reads like a printed ledger. */
.runbook { border-top: 1px solid var(--rule-strong); }

.runbook-row {
  display: grid;
  grid-template-columns: 12rem 1fr;
  gap: var(--s4);
  align-items: start;
  padding-block: var(--s4);
  border-bottom: 1px solid var(--rule);
}

.runbook-row h3 { margin: 0 0 0.25rem; }
.runbook-copy p { margin: 0; color: var(--graphite-soft); }

.runbook-label {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  padding-top: 0.3rem;
}

/* ------------------------------------------------- service rows (services page) */

/* Copy beside a piece of evidence. Two equal columns so the terminal block has
   room to be legible — it is the proof, not a thumbnail. */
.service-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: center;
  padding-block: var(--s5);
  border-bottom: 1px solid var(--rule);
}

.service-row:last-child { border-bottom: 0; }

.service-row h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); margin-bottom: var(--s2); }

/* Alternate which side the evidence sits on, without reordering the DOM —
   source order stays copy-then-visual, which is also the reading order on
   mobile once the columns collapse. */
.service-row.reverse .service-copy   { order: 2; }
.service-row.reverse .service-visual { order: 1; }

/* min-width:0 is load-bearing: without it the terminal's pre block refuses to
   shrink below its content width and overflows the grid column. */
.service-visual { min-width: 0; }

.service-copy { min-width: 0; }

/* Bulleted capability list inside the copy column. */
.service-copy .service-list {
  list-style: none;
  margin: var(--s3) 0 0;
  padding: 0;
  display: grid;
  gap: 0.6rem;
  border-top: 1px solid var(--rule);
  padding-top: var(--s3);
}

.service-copy .service-list li {
  position: relative;
  padding-left: 1.35rem;
  font-size: 0.9875rem;
  color: var(--graphite-soft);
}

/* En dash rather than a bullet or a check: this is a list of what is included,
   not a sales checklist. */
.service-copy .service-list li::before {
  content: "\2013";
  position: absolute;
  left: 0;
  color: var(--faint);
}

/* Legacy hooks kept so older markup does not collapse. */
.card { border: 1px solid var(--rule); border-radius: var(--r); padding: var(--s3); background: var(--paper-raised); }
.card-icon { display: none; }

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

.page-hero {
  padding-top: clamp(3rem, 7vw, 5rem);
  padding-bottom: var(--s5);
  border-bottom: 1px solid var(--rule);
}

.page-hero h1 { font-size: clamp(2.2rem, 5vw, 3.4rem); max-width: 18ch; }

/* ---------------------------------------------------------------- process */

.process { display: grid; gap: 0; border-top: 1px solid var(--rule-strong); }

.process-item {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  gap: var(--s3);
  padding-block: var(--s3);
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}

/* Numbers earn their place here: this genuinely is an ordered sequence. */
.process-num, .num {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--faint);
  letter-spacing: 0.08em;
}

.process-item h3 { margin-bottom: 0.25rem; }
.process-item p { margin: 0; color: var(--graphite-soft); font-size: 1rem; }



/* ---------------------------------------------------------------- coverage strip */

/* services.html. Same grammar as the ledger — hairline rule, tick divisions,
   mono labels — but saying something different: the span of the work, from a
   commit to a running system. Six zones because there are six services, so the
   diagram is an index of the page rather than decoration on top of it. */
.coverage {
  border-top: 1px solid var(--graphite);
  padding-top: var(--s2);
  margin-top: var(--s5);
}

.coverage-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s3);
}

.coverage-title,
.coverage-meta {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.coverage-title { color: var(--graphite); }
.coverage-meta  { color: var(--muted); letter-spacing: 0.06em; }

.coverage-chart { width: 100%; height: auto; display: block; overflow: visible; }

.cov-rule    { stroke: var(--rule-strong); stroke-width: 1; }
.cov-div     { stroke: var(--graphite); stroke-width: 1; }
.cov-endcap  { stroke: var(--graphite); stroke-width: 2; }
.cov-label   { fill: var(--graphite-soft); font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.04em; }
.cov-end     { fill: var(--faint); font-family: var(--mono); font-size: 9px; letter-spacing: 0.14em; }

/* Below the strip the six zone labels stack on narrow screens, where an SVG of
   angled text would be illegible. */
@media (max-width: 48rem) {
  .coverage-chart { display: none; }
  .coverage-list { display: grid; }
}

.coverage-list { display: none; gap: 0; margin: 0; padding: 0; list-style: none; }

.coverage-list li {
  display: flex;
  justify-content: space-between;
  gap: var(--s2);
  padding-block: 0.6rem;
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--graphite-soft);
}

.coverage-list li span { color: var(--faint); }

/* ---------------------------------------------------------------- principles */

/* about.html carries no diagram on purpose. A page arguing that infrastructure
   should be unremarkable does not get to arrive covered in ornament; the
   restraint is the argument. The list does the work instead. */
.principle-list { border-top: 1px solid var(--graphite); }

.principle {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  gap: var(--s3);
  align-items: baseline;
  padding-block: var(--s4);
  border-bottom: 1px solid var(--rule);
}

.principle-num {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--faint);
  letter-spacing: 0.08em;
}

.principle h3 { margin-bottom: 0.35rem; }
.principle p  { margin: 0; color: var(--graphite-soft); }

/* .principle has three children — number, heading, copy — against two columns,
   so the copy would auto-flow onto row 2 and land in the 3.5rem number column.
   Pin everything that is not the number to column 2. */
.principle > :not(.principle-num) { grid-column: 2; }

@media (max-width: 48rem) {
  .principle { grid-template-columns: 1fr; gap: 0.35rem; }

  /* Release the column pin, or the desktop rule forces an implicit second
     column and reintroduces the same narrow-strip bug on mobile. */
  .principle > :not(.principle-num) { grid-column: 1; }
}

/* ---------------------------------------------------------------- cta band */

.cta-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
}

.cta-band h2 { margin-bottom: 0.35rem; }
.cta-band p  { margin: 0; color: var(--graphite-soft); }

/* ---------------------------------------------------------------- next steps */

.next-steps { border-top: 1px solid var(--graphite); margin-top: var(--s5); padding-top: var(--s2); }

/* Sized as a label rather than a display heading: it is an h2 for document
   structure, not for visual weight. */
.next-steps-heading {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--graphite);
  margin: 0 0 var(--s3);
}

.next-steps .process-item:last-child { border-bottom: 0; }

.step-when {
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--faint);
  letter-spacing: 0.06em;
  display: block;
  margin-top: 0.3rem;
}

/* ---------------------------------------------------------------- terminal */

/* Real command output, set as a document rather than a fake window: no traffic
   lights, no glow. It is evidence, so it should look typeset. */
.term {
  background: var(--paper-raised);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r);
  overflow: hidden;
}

.term-bar {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem var(--s2);
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--muted);
  background: var(--paper-sunk);
}

.term-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--rule-strong); flex: none; }

.term-body {
  margin: 0;
  padding: var(--s3);
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.75;
  color: var(--graphite-soft);
  overflow-x: auto;
  white-space: pre;
}

.comment { color: var(--faint); }
.prompt  { color: var(--verdigris); }
.v       { color: var(--graphite); font-weight: 500; }

/* ---------------------------------------------------------------- forms */

.field { margin-bottom: var(--s3); }

.field label,
.field > span:first-child {
  display: block;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.45rem;
}

input, select, textarea {
  width: 100%;
  font-family: var(--body);
  font-size: 1rem;
  color: var(--graphite);
  background: var(--paper-raised);
  border: 1px solid var(--rule-strong);
  border-radius: var(--r);
  padding: 0.75rem 0.9rem;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--verdigris);
  box-shadow: 0 0 0 3px var(--verdigris-wash);
}

textarea { min-height: 9rem; resize: vertical; }

.form-status { font-size: 0.9375rem; margin-top: var(--s2); }
.form-status.ok  { color: var(--verdigris); }
.form-status.err { color: var(--rust); }

/* ---------------------------------------------------------------- check group */

/* A fieldset rather than a div, so the group has a real accessible name via
   <legend> — a checkbox group without one is just six unrelated boxes to a
   screen reader. */
.checkgroup {
  border: 0;
  margin: 0 0 var(--s3);
  padding: 0;
}

.checkgroup legend {
  padding: 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.35rem;
}

.checkgroup-hint {
  font-size: 0.875rem;
  color: var(--faint);
  margin: 0 0 0.75rem;
  max-width: none;
}

.checkgroup-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0.4rem 1.25rem;
}

.check {
  touch-action: manipulation;
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.4rem 0;
  cursor: pointer;
  font-size: 0.9375rem;
  color: var(--graphite-soft);
  line-height: 1.4;
}

/* Width must be reset: the global input rule sets width:100%, which would
   stretch each checkbox across its whole column. */
.check input[type="checkbox"] {
  width: auto;
  flex: none;
  margin: 0.15rem 0 0;
  accent-color: var(--verdigris);
}

.check:hover { color: var(--graphite); }

/* ---------------------------------------------------------------- reveals */

/* Scroll choreography. One motion, used everywhere: a short rise and settle.
   Repeating a single gesture reads as a system; a different effect per section
   reads as a demo reel.

   Scoped under .js-reveal, which is only set when JS runs AND motion is
   welcome. Without it these rules do not exist and the page renders normally —
   content is never hidden behind a script.

   transform and opacity only, so this stays on the compositor and cannot cause
   layout shift: elements occupy their final space from the start and are merely
   invisible. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
}

.js-reveal .reveal.is-in {
  opacity: 1;
  transform: none;
  /* Properties listed explicitly — `all` would animate layout properties too. */
  transition: opacity 620ms cubic-bezier(.22,.61,.36,1),
              transform 620ms cubic-bezier(.22,.61,.36,1);
}

/* Children stagger behind their parent so a section arrives as one movement.
   --d is set per item in the markup. */
.js-reveal .reveal-item {
  opacity: 0;
  transform: translateY(12px);
}

.js-reveal .is-in .reveal-item,
.js-reveal .reveal-item.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 520ms cubic-bezier(.22,.61,.36,1) calc(var(--d, 0) * 70ms),
              transform 520ms cubic-bezier(.22,.61,.36,1) calc(var(--d, 0) * 70ms);
}

/* The ledger is the signature, so it gets the one bespoke moment: ticks sweep
   in left to right, which is also the direction the data reads. Scaling from
   the baseline rather than the centre so they grow out of the axis. */
.js-reveal .ledger-chart .tick,
.js-reveal .ledger-chart .tick-incident {
  opacity: 0;
  transform: scaleY(0.25);
  transform-box: fill-box;
  transform-origin: bottom center;
}

.js-reveal .ledger.is-in .tick,
.js-reveal .ledger.is-in .tick-incident {
  opacity: 1;
  transform: none;
  transition: opacity 260ms ease-out calc(var(--t) * 9ms),
              transform 420ms cubic-bezier(.22,.61,.36,1) calc(var(--t) * 9ms);
}

/* The one incident lands last and a beat later than the sweep that precedes it,
   so the eye is drawn to it rather than it passing in the crowd. */
.js-reveal .ledger.is-in .tick-incident {
  transition-delay: 1100ms, 1100ms;
}

/* ---------------------------------------------------------------- pipeline */

/* The one animated element on the site. Motion is justified here because a
   pipeline IS a sequence — the animation shows cause and effect (this, then
   this, and a person in the middle) rather than decorating a static fact.
   Everything else on the page stays still on purpose.

   Input-driven rather than autoplay: nothing moves until someone asks, which
   also keeps it clear of the WCAG rule about motion running longer than five
   seconds alongside other content. */
.pipeline {
  border-top: 1px solid var(--graphite);
  padding-top: var(--s2);
  margin: 0;
}

.pipeline-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s3);
}

.pipeline-title {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--graphite);
}

.pipeline-run {
  touch-action: manipulation;
  font-family: var(--body);
  font-size: 0.8125rem;
  font-weight: 600;
  /* 24px minimum hit target. */
  min-height: 32px;
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r);
  background: var(--paper-raised);
  color: var(--graphite);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease;
}

/* Interaction states carry more contrast than rest. */
.pipeline-run:hover { border-color: var(--graphite); }

.pipe-chart { width: 100%; height: auto; display: block; overflow: visible; }

.pipe-track    { stroke: var(--rule-strong); stroke-width: 2; }
.pipe-progress { stroke: var(--verdigris); stroke-width: 2; }

/* scaleX on a wrapper <g> rather than animating x2, so only transform changes
   and the compositor can handle it. transform-box/origin are set explicitly
   because Safari miscalculates SVG transform origins without them. */
.pipe-progress-wrap {
  transform: scaleX(0);
  transform-box: fill-box;
  transform-origin: left center;
}

.pipe-ring  { fill: var(--paper); stroke: var(--rule-strong); stroke-width: 2; }
.pipe-fill  { fill: var(--verdigris); opacity: 0; }
.pipe-check { stroke: var(--paper); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; fill: none; opacity: 0; }

/* The human review gate is the only node drawn differently at rest — it is the
   step an unattended pipeline does not have. */
.pipe-node--gate .pipe-ring { stroke: var(--verdigris); stroke-dasharray: 3 3; }

.pipe-label {
  fill: var(--muted);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
}

/* --- running -------------------------------------------------------------- */

.pipeline.is-running .pipe-progress-wrap { animation: pipe-advance 3.4s cubic-bezier(.4,0,.2,1) forwards; }

/* Each node lights as the progress line reaches it. --i staggers the delay so
   the sequence reads as one movement rather than five separate blinks. */
.pipeline.is-running .pipe-fill  { animation: pipe-pop .35s ease-out forwards; animation-delay: calc(var(--i) * 0.68s + 0.2s); }
.pipeline.is-running .pipe-check { animation: pipe-pop .35s ease-out forwards; animation-delay: calc(var(--i) * 0.68s + 0.3s); }

@keyframes pipe-advance { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes pipe-pop     { from { opacity: 0; } to { opacity: 1; } }

/* Settled state, used when motion is reduced and after a run completes. */
.pipeline.is-done .pipe-progress-wrap { transform: scaleX(1); }
.pipeline.is-done .pipe-fill,
.pipeline.is-done .pipe-check { opacity: 1; }

.pipe-list { display: none; }

@media (max-width: 46rem) {
  .pipe-chart { display: none; }
  .pipeline-run { display: none; }
  .pipe-list { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; }
  .pipe-list li {
    display: flex; gap: 0.7rem; align-items: baseline;
    padding-block: 0.6rem; border-bottom: 1px solid var(--rule);
    font-size: 0.9375rem; color: var(--graphite-soft);
  }
  .pipe-list li span {
    font-family: var(--mono); font-size: 0.6875rem; color: var(--faint);
    font-variant-numeric: tabular-nums;
  }
}

/* ---------------------------------------------------------------- turnstile */

/* Reserve height so the form does not jump when the widget finishes loading.
   65px is Turnstile's rendered height in Managed mode. */
.turnstile {
  margin-bottom: var(--s3);
  min-height: 65px;
}

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

.site-footer {
  border-top: 1px solid var(--rule);
  padding-block: var(--s5) var(--s4);
  background: var(--paper-sunk);
}

.footer-top {
  display: grid;
  /* auto-fit rather than a fixed track count: pages carry different numbers of
     footer columns, and a fixed grid strands the odd one on its own row. */
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--s4);
  padding-bottom: var(--s4);
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: 0.09em;
  font-size: 0.9375rem;
  color: var(--graphite);
  text-decoration: none;
}

.footer-brand img {
  height: 30px;
  width: auto;
  border-radius: 2px;
}

.footer-col h3 {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--s2);
}

.footer-links { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.footer-links a { color: var(--graphite-soft); text-decoration: none; font-size: 0.9375rem; }
.footer-links a:hover { color: var(--graphite); text-decoration: underline; }

.footer-bottom {
  border-top: 1px solid var(--rule);
  padding-top: var(--s3);
  display: flex;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--faint);
  letter-spacing: 0.06em;
}

/* ---------------------------------------------------------------- responsive */

@media (max-width: 62rem) {
  .footer-top { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 48rem) {
  .nav-toggle { display: block; }

  .nav-links {
    display: none;
    position: absolute;
    left: 0; right: 0;
    top: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--s2);
    padding: var(--s3) var(--gutter) var(--s4);
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
  }

  .nav-links.open { display: flex; }
  .nav { position: relative; }
  .status-pill { display: none; }

  .runbook-row,
  .process-item { grid-template-columns: 1fr; gap: var(--s1); }
  .runbook-label { padding-top: 0; }

  .service-row { grid-template-columns: 1fr; gap: var(--s3); padding-block: var(--s4); }

  /* Reading order beats visual alternation once stacked: copy always leads. */
  .service-row.reverse .service-copy,
  .service-row.reverse .service-visual { order: 0; }

  .footer-top { grid-template-columns: 1fr; gap: var(--s3); }

  section { padding-block: var(--s5); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
