/*
 * The product site's own styling, over the shared tokens in `tokens.css`.
 *
 * The values are all in the token file, which all three surfaces read - what is here is
 * only what this surface has: a bar, a hero, and the card shapes.
 *
 * It matches the workbench deliberately. Same near-black ground, same hairline cards
 * that take their colour on hover, same graded ramp running indigo to lilac across a
 * row. Somebody who reads this page and then installs should not arrive somewhere
 * that looks like a different product.
 *
 * The bloom is drawn once per page, over the top of it, rather than tiled under the
 * whole document: full strength behind the hero (`.hero-shell`) and at a third of that
 * behind the other two (`.inner main`). Repeating a radial glow behind every paragraph
 * of the install guide was colour with no job - it marked nothing as more or less
 * important and made long-form text a little harder to read against. Lighting only the
 * top of a page is different: it says where the page begins.
 */

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--surface-sunken);
  min-height: 100vh;
  /* A column with a growing `main`, so the footer sits on the bottom of the viewport
     rather than halfway up it. The overview is one hero and two links and does not
     fill a screen - without this, the strip of small print lands under the buttons
     with the rest of the page empty below it, which reads as content that failed to
     load rather than a page that is simply short. */
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

main { flex: 1 0 auto; }

/* The same bloom the hero carries, at a third of the strength and only over the top of
   the page: enough that the capability and install pages open in the same room as the
   overview, not so much that it sits behind body text. `isolation` keeps the negative
   z-index inside `main`, so it paints under the content and over the page colour. */
.inner main { position: relative; isolation: isolate; }
.inner main::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 30rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    120% 100% at 50% -10%,
    color-mix(in srgb, var(--accent-2) 20%, transparent),
    transparent 68%
  );
}

code, pre { font-family: var(--mono); }
a { color: var(--accent); }

.skip-link {
  position: absolute;
  left: 8px;
  top: -48px;
  z-index: 20;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  transition: top 120ms ease;
}
.skip-link:focus { top: 8px; }

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

.wrap { max-width: 52rem; margin: 0 auto; padding: 3rem 1.5rem 4rem; }


/* ---------------------------------------------------------------- chrome */

.bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0 1.5rem;
  height: var(--topbar-h);
  border-bottom: 1px solid var(--line);
  background: color-mix(in oklab, var(--surface) 78%, transparent);
  backdrop-filter: blur(10px);
  position: sticky;
  top: 0;
  z-index: 10;
}
.bar__brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  color: var(--ink);
  text-decoration: none;
}
.bar__brand img { display: block; border-radius: 6px; transition: transform 220ms cubic-bezier(0.2, 0.7, 0.3, 1); }
.bar__brand:hover img { transform: scale(1.06) rotate(-3deg); }
.bar__nav { display: flex; gap: 0.25rem; margin-left: auto; }
.bar__nav a {
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--ink-muted);
  font-size: 0.95rem;
}
.bar__nav a:hover { color: var(--ink); background: var(--surface-sunken); }
.bar__nav a[aria-current='page'] { color: var(--accent); background: var(--accent-soft); }

.foot {
  border-top: 1px solid var(--line);
  background: transparent;
  color: var(--ink-muted);
  font-size: 0.9rem;
}
.foot p { max-width: 52rem; margin: 0 auto; padding: 1.5rem; }

/* ---------------------------------------------------------------- landing
 *
 * The hero draws its own background - a bloom plus a field of drifting pills, the
 * same shapes the workbench home page opens on - so a visitor who installs and
 * lands there recognises the room rather than arriving somewhere new.
 *
 * It fills the first screen. The version before this sized to its own content, which
 * on a 1440 display put four lines of text in the top third and left the rest black:
 * the page read as one that had failed to load the rest of itself. A first view is
 * the whole job of this page, so the shell claims the viewport and centres in it.
 */

/* The overview is exactly one screen, footer included. Sizing the shell to
   `100vh - topbar` instead left the footer hanging ~70px below the fold, so the one
   page built to fill the first view was also the one page that opened with a
   scrollbar. Letting it flex inside `main` makes the fit exact and keeps it exact if
   the footer ever wraps to a second line. `1 0 auto` rather than `1`: on a short
   window the hero keeps its own height and the page scrolls, instead of crushing. */
body:not(.inner) main { display: flex; flex-direction: column; }

.hero-shell {
  position: relative;
  overflow: hidden;
  flex: 1 0 auto;
  min-height: 32rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.hero-shell::before,
.hero-shell::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero-shell::before {
  background:
    linear-gradient(
      135deg,
      color-mix(in srgb, var(--accent-2) 8%, transparent),
      transparent 45%,
      color-mix(in srgb, var(--accent) 7%, transparent)
    ),
    var(--page-glow);
}

/* Fades the bloom back to the flat page colour at the shell's own bottom edge, so
   the footer picks up from the page colour rather than from a cut-off wash. */
.hero-shell::after {
  background: linear-gradient(to bottom, transparent 68%, var(--surface-sunken) 100%);
}

.hero__field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.hero__shape {
  position: absolute;
  transform: rotate(var(--rot));
  animation: hero-shape-in 1200ms cubic-bezier(0.23, 0.86, 0.39, 0.96) backwards;
  animation-delay: calc(var(--i) * 110ms + 140ms);
}

.hero__shape::before {
  content: "";
  display: block;
  width: var(--w);
  height: var(--h);
  border-radius: var(--radius-pill);
  border: 1px solid var(--accent-line);
  background:
    radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--accent) 18%, transparent), transparent 70%),
    linear-gradient(90deg, var(--tint), transparent 85%);
  backdrop-filter: blur(2px);
  animation: hero-shape-float 12s ease-in-out infinite;
}

.hero__shape--deep { --tint: color-mix(in srgb, var(--accent-2) 24%, transparent); }
.hero__shape--light { --tint: color-mix(in srgb, var(--accent) 18%, transparent); }

@keyframes hero-shape-in {
  from { opacity: 0; transform: translateY(-70px) rotate(calc(var(--rot) - 15deg)); }
  to   { opacity: 1; transform: translateY(0) rotate(var(--rot)); }
}

@keyframes hero-shape-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(12px); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__shape,
  .hero__shape::before { animation: none; }
}

/* Wider than the reading column the other two pages use, because the rail needs four
   stations across. Declared after `.wrap` so it wins on source order at equal
   specificity - if either selector is ever moved, this is the pair to keep in order. */
.hero__wrap {
  max-width: 70rem;
  width: 100%;
  padding-top: 4.5rem;
  padding-bottom: 4.5rem;
}

/* Positioned and given its own stacking order, so the text reads above the field and
   the bloom regardless of which of the three paints last in the document. */
.hero { position: relative; z-index: 1; }

/* The one loud thing on the page, and the only one. It is a sentence rather than the
   product name because a judge meeting Aegis for the first time can read what it does
   faster than they can infer it from a word - the name is on the bar, in the tab and
   in the line below, so nothing is lost by spending the largest type on the claim.
   Solid ink, not a gradient: at this size the scale is the emphasis, and a wash across
   it would be a second effect competing with the bloom behind it. */
.hero__claim {
  margin: 0;
  max-width: 17ch;
  font-size: clamp(2.5rem, 6vw, 4.4rem);
  line-height: 1.02;
  letter-spacing: -0.038em;
  font-weight: 560;
  text-wrap: balance;
}

/* The word that loops itself in and out - see `.hero__claim .typewriter` under
   arrival for the timing. Monospace only here, in the one place a fixed character
   width is load-bearing: it is what lets the reveal animate to an exact `ch` count
   instead of guessing at a proportional font's letterform widths. No letter-spacing -
   it is added after every character including the last, which pushed the final "S"
   a few pixels past the box `overflow: hidden` was clipping to. */
.hero__claim .typewriter {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  white-space: nowrap;
  font-family: var(--mono);
  border-right: 0.1em solid var(--accent);
}

.hero__lede {
  margin: 1.5rem 0 0;
  font-size: 1.1rem;
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: 54ch;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 0.7rem; margin: 2.5rem 0 0; }

.btn {
  display: inline-block;
  padding: 0.72rem 1.4rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  text-decoration: none;
  color: var(--ink);
  font-weight: 560;
  /* Translucent over the bloom rather than opaque, so the shapes drifting behind the
     hero pass under the secondary action instead of being punched out by it. */
  background: color-mix(in srgb, var(--surface-raised) 62%, transparent);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 6%);
  transition: border-color 200ms ease, color 200ms ease, transform 200ms cubic-bezier(0.2, 0.7, 0.3, 1), box-shadow 200ms ease;
}
.btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  transform: translateY(-2px);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 8%), 0 12px 30px -18px var(--accent);
}

/* The gradient stops short of `--accent` at the top: the full pair runs #a878ff to
   #6633ee, and white on #a878ff is 3.0:1, which fails on a 15px label. Mixed a third
   of the way it is 5.1:1 and still reads as the brand ramp rather than a flat fill. */
.btn--primary {
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 35%, var(--accent-2)), var(--accent-2));
  border-color: color-mix(in srgb, var(--accent) 45%, var(--accent-2));
  color: var(--accent-ink);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 24%),
    0 12px 30px -14px rgb(102 51 238 / 75%);
}
.btn--primary:hover {
  color: var(--accent-ink);
  border-color: var(--accent);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 28%),
    0 18px 42px -14px rgb(102 51 238 / 90%);
}

/* ---- the rail
 *
 * One line with four stops, not four cards. The claim above it is that context
 * survives the handover between stages; four separate boxes would illustrate the
 * opposite. The line is the only decoration on the page that carries an argument,
 * which is why it is the only one here at all.
 *
 * It fades at both ends rather than stopping square: the four surfaces are where the
 * workbench happens to have a page, not the ends of the thing.
 */
.rail {
  position: relative;
  z-index: 1;
  margin-top: clamp(3.5rem, 8vh, 6rem);
}
.rail__lede {
  margin: 0 0 1.5rem;
  font-size: var(--fs-small);
  color: var(--ink-muted);
}
/* The padding that clears the line belongs to each station, not to the list: the pin
   is positioned against its own station, so if the list holds the offset the pin lands
   above its station box and sits on top of the first line of text. */
.rail__stations {
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.rail__stations::before {
  content: "";
  position: absolute;
  top: 5px;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    var(--accent-line) 6%,
    color-mix(in srgb, var(--accent) 38%, transparent) 50%,
    var(--accent-line) 94%,
    transparent
  );
}

.station { position: relative; padding-top: 2.2rem; }
/* A diamond on the line, filled with the brand ramp - the same two stops in the same
   order as every other gradient in the product, which is what makes it read as one
   mark repeated rather than four dots. */
.station__pin {
  position: absolute;
  top: 0;
  left: 0;
  width: 11px;
  height: 11px;
  border-radius: 2px;
  transform: rotate(45deg);
  background: var(--accent-grad);
  box-shadow: 0 0 0 4px var(--surface-sunken), 0 0 18px -2px var(--accent);
}
.station__asks {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--ink-muted);
}
.station__name {
  margin: 0.15rem 0 0;
  font-size: 1.15rem;
  font-weight: 560;
  letter-spacing: -0.015em;
}
.station__path {
  display: inline-block;
  margin-top: 0.3rem;
  font-size: var(--fs-meta);
  color: var(--accent);
}

/* Below five-across the line stops meaning anything - it would run behind two stacked
   rows and connect stations that are not beside each other - so it goes, and each pin
   becomes the bullet of its own entry. */
@media (max-width: 64rem) {
  .rail__stations { grid-template-columns: repeat(3, 1fr); gap: 1.75rem 1.5rem; }
  .rail__stations::before { display: none; }
  .station { padding: 0 0 0 1.4rem; }
  .station__pin { top: 0.42rem; box-shadow: 0 0 14px -2px var(--accent); }
  .station--gate .station__pin { box-shadow: none; }
}

@media (max-width: 52rem) {
  .rail__stations { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 30rem) {
  .rail__stations { grid-template-columns: 1fr; }
  .hero__wrap { padding-top: 3rem; padding-bottom: 3rem; }
}

/* ---------------------------------------------------------------- capabilities */

h1 { font-size: 2.2rem; margin: 0 0 0.5rem; letter-spacing: -0.02em; }
.lede { margin: 0 0 1rem; font-size: 1.1rem; color: var(--ink-muted); }
/* The two halves of the capability page. A label rather than a heading, because the
   seven things under it are the sections - another heading level above them would push
   the families to a fourth. */
.part {
  margin: 3rem 0 0;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--line-strong);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

.group { margin-top: 2.5rem; }
.group h2 { margin: 0 0 0.2rem; font-size: 1.35rem; display: flex; align-items: baseline; gap: 0.5rem; }
.group__count {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--ink-faint);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0 0.5rem;
}

/* The four surfaces. A grid rather than four stacked sections, because they are peers -
   stacked, the order reads as a sequence one has to go through. */
.tiles {
  display: grid;
  gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  margin-top: 1.5rem;
}
/* Depth from a lit top edge and a shadow the brand colour, not from a fill gradient:
   the token file's own note says the vertical fade inside a panel cost legibility,
   because text at its top sat on a different value than text at its bottom. A 1px
   inset highlight lifts the card without touching the value the text sits on. */
.tile {
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 1.35rem 1.4rem;
  background: var(--panel-bg);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 5%),
    0 14px 34px -26px rgb(0 0 0 / 80%);
  transition: border-color 220ms ease, transform 220ms cubic-bezier(0.2, 0.7, 0.3, 1), box-shadow 220ms ease;
}
.tile:hover {
  transform: translateY(-2px);
  border-color: var(--accent-line);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 7%),
    0 20px 44px -22px rgb(102 51 238 / 62%);
}
.tile h2 { margin: 0; font-size: 1.15rem; display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.4rem; }
.tile__aka { font-size: 0.8rem; font-weight: 500; color: var(--ink-faint); }
.tile__path { display: inline-block; margin: 0.25rem 0 0.7rem; font-size: 0.85rem; color: var(--ink-faint); }
.tile__what { margin: 0; color: var(--ink-muted); font-size: 0.92rem; }

/* A family is a label over its grid, not a section that indents. At this density the
   old left rule and heading weight were more structure than nineteen short cards
   need - the label says which shelf you are on and the grid does the rest. */
.family { margin: 1.75rem 0 0; }
.family__name {
  margin: 0 0 0.7rem;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
}

/* One shape, repeated. Every capability is the same size on the page because every
   capability is the same kind of thing, and a grid of equals is readable at a glance
   in a way a stack of expandable rows is not. */
.caps {
  display: grid;
  gap: 0.75rem;
  /* Three to a row in the reading column. Wider and a family of three wraps to two
     rows for no reason; narrower and the clamped description loses its second line. */
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
/* The card is the link. `display: block` and inherited colour so it reads as a card
   rather than as a paragraph of link text, and the chevron is the affordance that says
   there is a page behind it - drawn in CSS because the site ships no icon font and a
   glyph in the markup would be read aloud. */
.cap {
  position: relative;
  display: block;
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.85rem 2.1rem 0.85rem 1rem;
  background: var(--panel-bg);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%);
  color: inherit;
  text-decoration: none;
  transition: border-color 200ms ease, box-shadow 200ms ease, transform 200ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.cap::after {
  content: "";
  position: absolute;
  top: 1.15rem;
  right: 1rem;
  width: 6px;
  height: 6px;
  border-top: 1.5px solid var(--ink-faint);
  border-right: 1.5px solid var(--ink-faint);
  transform: rotate(45deg);
  transition: border-color 200ms ease, transform 200ms ease;
}
.cap:target,
.cap:hover,
.cap:focus-visible {
  border-color: var(--accent-line);
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 7%),
    0 14px 30px -20px rgb(102 51 238 / 80%);
}
.cap:hover::after,
.cap:focus-visible::after {
  border-color: var(--accent);
  transform: rotate(45deg) translate(1.5px, -1.5px);
}
.cap__head { display: flex; align-items: center; gap: 0.5rem; }
.cap__id { font-weight: 600; font-size: 0.92rem; }
/* Clamped, not cut: the whole sentence is in the markup, so Ctrl-F finds it and a
   screen reader reads it - the card just does not spend four lines on it. Two lines
   keeps every card in a row the same height without a fixed height, which is what
   makes the grid read as a grid. */
.cap__desc {
  margin: 0.4rem 0 0;
  color: var(--ink-muted);
  font-size: 0.88rem;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

/* The fifth stop, and the fifth tile, are the quality gate. Both are marked with a
   dashed rule rather than a solid one and a muted slot where the others print a URL:
   the four are places you can open, this is a moment in the pipeline, and a reader
   should be able to see that without reading it. */
.tile--gate { border-style: dashed; border-color: var(--line-strong); }
.tile--gate .tile__path,
.station--gate .station__path { color: var(--ink-faint); }
.station--gate .station__pin {
  background: none;
  border: 1.5px solid var(--accent);
  box-shadow: 0 0 0 4px var(--surface-sunken);
}

/* ---------------------------------------------------------------- the gate
 *
 * Three cards rather than prose, because the three authorities are a fixed set with a
 * strict order of power and that reads faster as three boxes than as a sentence with
 * two semicolons in it. `Verdict` first: it is the only one that can stop anything. */

.gate { margin-top: 2.5rem; }
.gate h2 { margin: 0 0 0.3rem; font-size: var(--fs-head); }
.gate__lede { margin: 0; color: var(--ink-muted); max-width: 72ch; }

.authorities {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  margin: 1.35rem 0 0;
}
.authority {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.85rem 1rem;
  background: var(--panel-bg);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%);
}
.authority dt { font-weight: 600; font-size: 0.95rem; }
.authority dd {
  margin: 0.4rem 0 0;
  color: var(--ink-muted);
  font-size: 0.88rem;
  line-height: 1.5;
}

.gate__note { margin: 1.35rem 0 0; color: var(--ink-muted); font-size: 0.92rem; max-width: 72ch; }

/* ---------------------------------------------------------- one capability
 *
 * The page behind a card. It is a reading page, so it keeps a measure rather than
 * running to the column edge, and it leads with the way back - somebody who arrived
 * here from the grid is one of nineteen decisions in and will want the other eighteen.
 */

.detail { max-width: 46rem; }

.detail__back { margin: 0 0 2rem; font-size: var(--fs-small); }
.detail__back a {
  position: relative;
  padding-left: 0.95rem;
  color: var(--ink-muted);
  text-decoration: none;
}
.detail__back a::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.42em;
  width: 6px;
  height: 6px;
  border-left: 1.5px solid currentcolor;
  border-bottom: 1.5px solid currentcolor;
  transform: rotate(45deg);
  transition: transform 180ms ease;
}
.detail__back a:hover { color: var(--accent); }
.detail__back a:hover::before { transform: rotate(45deg) translate(-1.5px, 1.5px); }

.detail__where {
  margin: 0 0 0.5rem;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
}
.detail__id {
  margin: 0 0 0.9rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.7rem;
  font-size: clamp(1.7rem, 3.4vw, 2.3rem);
  letter-spacing: -0.02em;
}
.detail__id code { font-size: inherit; font-weight: 600; }
.detail .lede { font-size: 1.1rem; color: var(--ink); }
.detail__long { margin: 1.1rem 0 0; color: var(--ink-muted); }

/* A definition list, because that is what these are. The grid keeps the labels in one
   column so the values line up down the page - four rows of `label: value` set inline
   would put every value at a different x. */
.facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.75rem 1.5rem;
  margin: 2.5rem 0 0;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.fact { display: contents; }
.facts dt {
  font-size: var(--fs-small);
  color: var(--ink-faint);
}
.facts dd {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.facts code {
  font-size: var(--fs-meta);
  background: var(--surface-raised-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.1rem 0.5rem;
}

/* The two-column grid needs both columns to fit; below this the label sits above its
   values instead, which is the same information one turn further down the page. */
@media (max-width: 34rem) {
  .facts { grid-template-columns: 1fr; gap: 0.3rem; }
  .fact { display: block; margin-bottom: 1rem; }
  .facts dd { margin-top: 0.35rem; }
}

/* ---------------------------------------------------------------- prose */

.prose h1 { margin-bottom: 1.5rem; }
.prose h2 { margin: 2.5rem 0 0.6rem; font-size: 1.4rem; }
.prose h3 { margin: 1.8rem 0 0.4rem; font-size: 1.1rem; }
.prose p, .prose li { color: var(--ink-muted); }
.prose strong { color: var(--ink); }
.prose ul { padding-left: 1.2rem; }
.prose li { margin-bottom: 0.4rem; }
.prose code {
  font-size: 0.9em;
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.08em 0.35em;
}
/* Sunken rather than raised - a command is something you read out of the page, not a
   panel sitting on it - with the same lit top edge every other surface here carries so
   the three pages read as one set of materials. */
.prose pre {
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0.9rem 1.1rem;
  overflow-x: auto;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 4%);
}
.prose pre code { background: none; border: 0; padding: 0; font-size: 0.88rem; }

/* A structured table - the commands reference, currently the only table this page
   renders - rather than the bare rows a browser draws with no styling at all. One
   card with a lifted header, the same shape as `.card`/`.tile`, so a table reads as
   a surface rather than as unstyled markdown that slipped through. */
.prose table {
  width: 100%;
  margin: 1.75rem 0;
  border-collapse: separate;
  border-spacing: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  font-size: 0.95rem;
}
.prose th {
  text-align: left;
  padding: 0.85rem 1.3rem;
  background: var(--surface-raised);
  color: var(--accent);
  font-weight: 650;
  border-bottom: 1px solid var(--line);
}
.prose td {
  padding: 1rem 1.3rem;
  color: var(--ink-muted);
  vertical-align: top;
}
/* Only between body rows - the header already carries its own bottom border, and a
   second one on top of the first body row would double it. */
.prose tbody tr + tr td { border-top: 1px solid var(--line); }
/* The command itself never wraps - a flag splitting across two lines reads as two
   different tokens. */
.prose td:first-child { white-space: nowrap; }

/* ---------------------------------------------------------------- arrival
 *
 * One orchestrated moment on load and nothing after it unless a person does
 * something: the claim, its line, the actions, then the rail drawing itself in from
 * the left. Four stations arriving in order is the only place the page implies a
 * direction, and it implies the right one - the thread runs left to right, which is
 * the argument the rail is making. Static HTML, so this is CSS and nothing else.
 *
 * The one exception is the brand word in the claim, which types itself in, sits,
 * erases and retypes for as long as the page is open - a cursor left waiting at a
 * prompt rather than a one-shot flourish, and the single place this page repeats
 * itself instead of settling.
 */
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes pin-in { from { opacity: 0; transform: rotate(45deg) scale(0.4); } to { opacity: 1; transform: rotate(45deg) scale(1); } }
/* Four widths, not two: type to full, hold there, erase to nothing, hold empty, then
   the `infinite` repeat starts the same cycle over. `steps(5, end)` is set on the 0%
   and 55% stops rather than on the animation shorthand, because a timing function set
   there governs only the segment leaving that stop - the two holds in between stay
   unaffected (their width does not move, so any easing over them looks identical) and
   only the type and erase segments land on whole letters instead of sweeping through
   them. */
@keyframes aegis-type {
  0%   { width: 0; animation-timing-function: steps(5, end); }
  15%  { width: 5ch; }
  55%  { width: 5ch; animation-timing-function: steps(5, end); }
  70%  { width: 0; }
  100% { width: 0; }
}
/* Blinks continuously - through the holds, and right across the type and erase
   segments too - the way a cursor does at a live prompt regardless of whether
   anything is being typed. A separate animation and clock from `aegis-type`, so nudging
   one's timing never has to touch the other's. */
@keyframes aegis-caret { 0%, 100% { border-color: var(--accent); } 50% { border-color: transparent; } }

.hero__claim { animation: rise 520ms ease backwards; }
/* Starts once the heading has finished rising in, so nobody watches the loop begin
   while the claim itself is still fading into view. */
.hero__claim .typewriter {
  width: 0;
  animation:
    aegis-type 4200ms linear 520ms infinite,
    aegis-caret 760ms step-end 520ms infinite;
}
.hero__lede { animation: rise 520ms ease 90ms backwards; }
.hero__actions { animation: rise 520ms ease 180ms backwards; }
.rail__lede { animation: rise 520ms ease 320ms backwards; }
.rail__stations::before {
  transform-origin: left center;
  animation: draw 900ms cubic-bezier(0.22, 0.75, 0.3, 1) 380ms backwards;
}
.station__asks,
.station__name,
.station__path { animation: rise 460ms ease backwards; animation-delay: calc(var(--i) * 110ms + 520ms); }
.station__pin { animation: pin-in 420ms cubic-bezier(0.2, 0.9, 0.3, 1.2) backwards; animation-delay: calc(var(--i) * 110ms + 460ms); }

@media (prefers-reduced-motion: reduce) {
  .hero__claim, .hero__lede, .hero__actions,
  .rail__lede, .rail__stations::before,
  .station__asks, .station__name, .station__path, .station__pin { animation: none; }
  /* The word still reads AEGIS - it just arrives whole rather than letter by letter,
     and the caret stops rather than blinking forever with nothing left to type. */
  .hero__claim .typewriter { width: 5ch; animation: none; border-right-color: transparent; }
  .tile:hover, .btn:hover { transform: none; }
  .bar__brand:hover img { transform: none; }
}
